Friday, April 24, 2015

Arduino Heart Rate Monitor


Project Description


Heart Rate Monitors are very popular at the moment.
There is something very appealing about watching the pattern of your own heart beat. And once you see it, there is an unstoppable urge to try and control it. This simple project will allow you to visualize your heart beat, and will calculate your heart rate. Keep reading to learn how to create your very own heart rate monitor.


 

Parts Required:


Fritzing Sketch


 

 
 
 

Grove Base Shield to Module Connections


 


 

Arduino Sketch


 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/* =================================================================================================
      Project: Arduino Heart rate monitor
       Author: Scott C
      Created: 21st April 2015
  Arduino IDE: 1.6.2
      Website: http://arduinobasics.blogspot.com/p/arduino-basics-projects-page.html
  Description: This is a simple sketch that uses a Grove Ear-clip Heart Rate sensor attached to an Arduino UNO,
               which sends heart rate data to the computer via Serial communication. You can see the raw data
               using the Serial monitor on the Arduino IDE, however, this sketch was specifically
               designed to interface with the matching Processing sketch for a much nicer graphical display.
               NO LIBRARIES REQUIRED.
=================================================================================================== */

#define Heart 2                            //Attach the Grove Ear-clip sensor to digital pin 2.
#define LED 4                              //Attach an LED to digital pin 4

boolean beat = false; /* This "beat" variable is used to control the timing of the Serial communication
                                           so that data is only sent when there is a "change" in digital readings. */

//==SETUP==========================================================================================
void setup() {
  Serial.begin(9600); //Initialise serial communication
  pinMode(Heart, INPUT); //Set digital pin 2 (heart rate sensor pin) as an INPUT
  pinMode(LED, OUTPUT); //Set digital pin 4 (LED) to an OUTPUT
}


//==LOOP============================================================================================
void loop() {
  if(digitalRead(Heart)>0){ //The heart rate sensor will trigger HIGH when there is a heart beat
    if(!beat){ //Only send data when it first discovers a heart beat - otherwise it will send a high value multiple times
      beat=true; //By changing the beat variable to true, it stops further transmissions of the high signal
      digitalWrite(LED, HIGH); //Turn the LED on
      Serial.println(1023); //Send the high value to the computer via Serial communication.
    }
  } else { //If the reading is LOW,
    if(beat){ //and if this has just changed from HIGH to LOW (first low reading)
      beat=false; //change the beat variable to false (to stop multiple transmissions)
      digitalWrite(LED, LOW); //Turn the LED off.
      Serial.println(0); //then send a low value to the computer via Serial communication.
    }
  }
}


 
 
 
 

Processing Sketch


 
  1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214

/* =================================================================================================
       Project: Arduino Heart rate monitor
        Author: Scott C
       Created: 21st April 2015
Processing IDE: 2.2.1
       Website: http://arduinobasics.blogspot.com/p/arduino-basics-projects-page.html
   Description: A Grove Ear-clip heart rate sensor allows an Arduino UNO to sense your pulse.
                The data obtained by the Arduino can then be sent to the computer via Serial communication
                which is then displayed graphically using this Processing sketch.
                
=================================================================================================== */

import processing.serial.*; // Import the serial library to allow Serial communication with the Arduino

int numOfRecs = 45; // numOfRecs: The number of rectangles to display across the screen
Rectangle[] myRecs = new Rectangle[numOfRecs]; // myRecs[]: Is the array of Rectangles. Rectangle is a custom class (programmed within this sketch)

Serial myPort;                                         
String comPortString="0"; //comPortString: Is used to hold the string received from the Arduino
float arduinoValue = 0; //arduinoValue: Is the float variable converted from comPortString
boolean beat = false; // beat: Used to control for multiple high/low signals coming from the Arduino

int totalTime = 0; // totalTime: Is the variable used to identify the total time between beats
int lastTime = 0; // lastTime: Is the variable used to remember when the last beat took place
int beatCounter = 0; // beatCounter: Is used to keep track of the number of beats (in order to calculate the average BPM)
int totalBeats = 10; // totalBeats: Tells the computer that we want to calculate the average BPM using 10 beats.
int[] BPM = new int[totalBeats]; // BPM[]: Is the Beat Per Minute (BPM) array - to hold 10 BPM calculations
int sumBPM = 0; // sumBPM: Is used to sum the BPM[] array values, and is then used to calculate the average BPM.
int avgBPM = 0; // avgBPM: Is the variable used to hold the average BPM calculated value.

PFont f, f2; // f & f2 : Are font related variables. Used to store font properties.


//==SETUP==============================================================================================
void setup(){
  size(displayWidth,displayHeight); // Set the size of the display to match the monitor width and height
  smooth(); // Draw all shapes with smooth edges.
  f = createFont("Arial",24); // Initialise the "f" font variable - used for the "calibrating" text displayed at the beginning
  f2 = createFont("Arial",96); // Initialise the "f2" font variable - used for the avgBPM display on screen
  
  for(int i=0; i<numOfRecs; i++){ // Initialise the array of rectangles
    myRecs[i] = new Rectangle(i, numOfRecs);
  }
  
  for(int i=0; i<totalBeats; i++){ // Initialise the BPM array
    BPM[i] = 0;
  }
  
  myPort = new Serial(this, Serial.list()[0], 9600); // Start Serial communication with the Arduino using a baud rate of 9600
  myPort.bufferUntil('\n'); // Trigger a SerialEvent on new line
}


//==DRAW==============================================================================================
void draw(){
  background(0); // Set the background to BLACK (this clears the screen each time)
  drawRecs();                                           // Method call to draw the rectangles on the screen
  drawBPM();                                            // Method call to draw the avgBPM value to the top right of the screen
}


//==drawRecs==========================================================================================
void drawRecs(){ // This custom method will draw the rectangles on the screen
  myRecs[0].setSize(arduinoValue);                      // Set the first rectangle to match arduinoValue; any positive value will start the animation.
  for(int i=numOfRecs-1; i>0; i--){ // The loop counts backwards for coding efficiency - and is used to draw all of the rectangles to screen
    myRecs[i].setMult(i);                               // setMulti creates the specific curve pattern.
    myRecs[i].setRed(avgBPM);                           // The rectangles become more "Red" with higher avgBPM values
    myRecs[i].setSize(myRecs[i-1].getH());              // The current rectangle size is determined by the height of the rectangle immediately to it's left
    fill(myRecs[i].getR(),myRecs[i].getG(), myRecs[i].getB()); // Set the colour of this rectangle
    rect(myRecs[i].getX(), myRecs[i].getY(), myRecs[i].getW(), myRecs[i].getH()); // Draw this rectangle
  }
}


//==drawBPM===========================================================================================
void drawBPM(){ // This custom method is used to calculate the avgBPM and draw it to screen.
  sumBPM = 0;                                           // Reset the sumBPM variable
  avgBPM = 0;                                           // Reset the avgBPM variable
  boolean calibrating = false; // calibrating: this boolean variable is used to control when the avgBPM is displayed to screen
  
  for(int i=1; i<totalBeats; i++){
    sumBPM = sumBPM + BPM[i-1];                         // Sum all of the BPM values in the BPM array.
    if(BPM[i-1]<1){ // If any BPM values are equal to 0, then set the calibrating variable to true.
      calibrating = true; // This will be used later to display "calibrating" on the screen.
    }
  }
  avgBPM = sumBPM/(totalBeats-1);                       // Calculate the average BPM from all BPM values
                                                        
  fill(255); // The text will be displayed as WHITE text
  if(calibrating){
    textFont(f);
    text("Calibrating", (4*width)/5, (height/5)); // If the calibrating variable is TRUE, then display the word "Calibrating" on screen
    fill(0); // Change the fill and stroke to black (0) so that other text is "hidden" while calibrating variable is TRUE
    stroke(0);
  } else {
    textFont(f2);
    text(avgBPM, (4*width)/5, (height/5)); // If the calibrating variable is FALSE, then display the avgBPM variable on screen
    stroke(255); // Change the stroke to white (255) to show the white line underlying the word BPM.
  }
  
   textFont(f);
   text("BPM", (82*width)/100, (height/11)); // This will display the underlined word "BPM" when calibrating variable is FALSE.
   line((80*width)/100, (height/10),(88*width)/100, (height/10));
   stroke(0);
}


//==serialEvent===========================================================================================
void serialEvent(Serial cPort){ // This will be triggered every time a "new line" of data is received from the Arduino
 comPortString = cPort.readStringUntil('\n'); // Read this data into the comPortString variable.
 if(comPortString != null) { // If the comPortString variable is not NULL then
   comPortString=trim(comPortString); // trim any white space around the text.
   int i = int(map(Integer.parseInt(comPortString),1,1023,1,height)); // convert the string to an integer, and map the value so that the rectangle will fit within the screen.
   arduinoValue = float(i); // Convert the integer into a float value.
   if (!beat){
     if(arduinoValue>0){ // When a beat is detected, the "trigger" method is called.
       trigger(millis()); // millis() creates a timeStamp of when the beat occured.
       beat=true; // The beat variable is changed to TRUE to register that a beat has been detected.
     }
   }
   if (arduinoValue<1){ // When the Arduino value returns back to zero, we will need to change the beat status to FALSE.
     beat = false;
   }
 }



//==trigger===========================================================================================
void trigger(int time){ // This method is used to calculate the Beats per Minute (BPM) and to store the last 10 BPMs into the BPM[] array.
  totalTime = time - lastTime;                         // totalTime = the current beat time minus the last time there was a beat.
  lastTime = time;                                     // Set the lastTime variable to the current "time" for the next round of calculations.
  BPM[beatCounter] = 60000/totalTime;                  // Calculate BPM from the totalTime. 60000 = 1 minute.
  beatCounter++;                                       // Increment the beatCounter
  if (beatCounter>totalBeats-1){ // Reset the beatCounter when the total number of BPMs have been stored into the BPM[] array.
    beatCounter=0;                                     // This allows us to keep the last 10 BPM calculations at all times.
  }
}


//==sketchFullScreen==========================================================================================
boolean sketchFullScreen() { // This puts Processing into Full Screen Mode
 return true;
}


//==Rectangle CLASS==================================================================================*********
class Rectangle{
  float xPos, defaultY, yPos, myWidth, myHeight, myMultiplier; // Variables used for drawing rectangles
  int blueVal, greenVal, redVal; // Variables used for the rectangle colour
  
  Rectangle(int recNum, int nRecs){ // The rectangles are constructed using two variables. The total number of rectangles to be displayed, and the identification of this rectangle (recNum)
    myWidth = displayWidth/nRecs; // The width of the rectangle is determined by the screen width and the total number of rectangles.
    xPos = recNum * myWidth;                                      // The x Position of this rectangle is determined by the width of the rectangles (all same) and the rectangle identifier.
    defaultY=displayHeight/2; // The default Y position of the rectangle is half way down the screen.
    yPos = defaultY;                                              // yPos is used to adjust the position of the rectangle as the size changes.
    myHeight = 1;                                                 // The height of the rectangle starts at 1 pixel
    myMultiplier = 1;                                             // The myMultiplier variable will be used to create the funnel shaped path for the rectangles.
    redVal = 0;                                                   // The red Value starts off being 0 - but changes with avgBPM. Higher avgBPM means higher redVal
    
    if (recNum>0){ // The blue Value progressively increases with every rectangle (moving to the right of the screen)
      blueVal = (recNum*255)/nRecs;
    } else {
      blueVal = 0;
    }
    greenVal = 255-blueVal;                                       // Initially, the green value is at the opposite end of the spectrum to the blue value.
  }
  
  void setSize(float newSize){ // This is used to set the new size of each rectangle
    myHeight=newSize*myMultiplier;
    yPos=defaultY-(newSize/2);
  }
  
  void setMult(int i){ // The multiplier is a function of COS, which means that it varies from 1 to 0.
    myMultiplier = cos(radians(i)); // You can try other functions to experience different effects.
  }
  
  void setRed(int r){
    redVal = int(constrain(map(float(r), 60, 100, 0, 255),0,255)); // setRed is used to change the redValue based on the "normal" value for resting BPM (60-100).
    greenVal = 255 - redVal;                                       // When the avgBPM > 100, redVal will equal 255, and the greenVal will equal 0.
  }                                                                // When the avgBPM < 60, redVal will equal 0, and greenVal will equal 255.
  
  float getX(){ // get the x Position of the rectangle
    return xPos;
  }
 
  float getY(){ // get the y Position of the rectangle
    return yPos;
  }
  
  float getW(){ // get the width of the rectangle
    return myWidth;
  }
  
  float getH(){ // get the height of the rectangle
    return myHeight;
  }
  
  float getM(){ // get the Multiplier of the rectangle
    return myMultiplier;
  }
  
  int getB(){ // get the "blue" component of the rectangle colour
    return blueVal;
  }
  
  int getR(){ // get the "red" component of the rectangle colour
    return redVal;
  }
  
  int getG(){ // get the "green" component of the rectangle colour
    return greenVal;
  }
}


 

Processing Code Discussion:


The Rectangle class was created to store relevant information about each rectangle. By using a custom class, we were able to design our rectangles any way we wanted. These rectangles have properties and methods which allow us to easily control their position, size and colour. By adding some smart functionality to each rectangle, we were able to get the rectangle to automatically position and colour itself based on key values.

The Serial library is used to allow communication with the Arduino. In this Processing sketch, the values obtained from the Arduino were converted to floats to allow easy calulations of the beats per minute (BPM). I am aware that I have over-engineered the serialEvent method somewhat, because the Arduino is only really sending two values. I didn't really need to convert the String. But I am happy with the end result, and it does the job I needed it to...


This project is quite simple. I designed it so that you could omit the Processing code if you wanted to. In that scenario, you would only be left with a blinking LED that blinks in time with your pulse. The Processing code takes this project to the next level. It provides a nice animation and calculates the beats per minute (BPM).
 
I hope you liked this tutorial. Please feel free to share it, comment or give it a plus one. If you didn't like it, I would still appreciate your constructive feedback.

 



If you like this page, please do me a favour and show your appreciation :

 
Visit my ArduinoBasics Google + page.
Follow me on Twitter by looking for ScottC @ArduinoBasics.
I can also be found on Pinterest and Instagram.
Have a look at my videos on my YouTube channel.


 
 



 
 
 



However, if you do not have a google profile...
Feel free to share this page with your friends in any way you see fit.




Monday, April 13, 2015

One Arduino


Arduino

is an "open source physical computing platform based on a simple microcontroller board". It is also a "development environment for writing software for the board" (Source: Arduino.cc). The first Arduino was born in 2005 in the classrooms of Interactive Design Institute in Ivrea, Italy. A nice presentation which shows a timeline of "how Arduino came to be" can be found here.
 
Arduino has been a very successful concept and creation. Ten years on, it has become one of, if not, the most popular prototyping and development platforms in the world. It has found it's way into the hearts of many makers, artists, programmers, developers and inventors. It has been used for millions of projects: from automatic garage door openers and tea makers to flamethrowers, robots, lighting displays and sound production. In fact, I cannot think of anything that the Arduino hasn't been used for.
 
But as you are pretty well aware, there has been a recent rift between the original founders of Arduino.
There is no need to go over the details here because it has been covered many times already on other sites. But if you would like to get up to speed on the Arduino Trademark dispute, I would suggest you read the following articles:
 
  1) Massimo Banzi's interview on Make
  2) Federico's letter to the makers on Arduino.org
  3) Court Transcripts from the United States Courts Archive
  4) What's in a name: The battle for the soul of Arduino - on ZD Net
  5) Arduino vs Arduino: Part II on Hackaday


 



My Letter to Arduino LLC/SRL


Why can't you get along? Why the deception? Why the greed?
 
Who does this benefit? It is a lose-lose battle, not only for Arduino SRL/LLC but for the whole Arduino community. We all love Arduino. We love the idea, the mission and the dream. We like to make things... We don't care who "the original" Arduino was or is. It doesn't matter. We just want...

We don't want different versions of the Arduino IDE (1.6.3 vs 1.7.0).
Some may say that you should redo the IDE altogether, but that is an entirely different topic :)

Can't you see what this is doing?
It is hard enough for tutorial makers and forum dwellers to keep up with the ever evolving IDE as it is. Making two different versions of the "same IDE" adds about 10 layers of confusion and complexity ! And for what ??? This will be confusing for the newbie, confusing for the helpers, the developers, for everyone.

I am guessing that my words will have no influence over your decisions. But I hope it does !
I plee with both of you to stand by your infinity symbol and work through your differences. Say what you need to say, but get back together and regroup - as ONE ARDUINO.

Your rift is likely to reverberate through to the Arduino Community aswell. Some people will side with Arduino LLC, some with Arduino SRL. And while some people will take a stance of indifference, there will be some that just look elsewhere.
 
I don't know if revealing the results of my poll will benefit the cause or add salt to the wounds, But I asked the question, and you probably want to know the answer. Who does the Arduino Community support right now?
 
The infographic below shows the results of the poll I posted a week ago:

This poll was posted on the Arduino Tutorial Google+ community page . I tried to be as unbiased as possible. People were only allowed to vote once (enforced by log in). Each voter would have been presented with the organisations in random order. And results were not published until now. The results above are accurate as of 14th April 2015 at 9am (in Australia)
 

As you can clearly see, Arduino LLC is highly favoured.
 
My personal preference is not captured by that infographic. I agree with the bald engineer, I would prefer #OneArduino. I would like the Arduino Community to stand united. I also want the Arduino founders to stand united! Please, work through your issues, stop being greedy and stop the deception. Arduino is more than a product. It is the heart of a greater movement.

This war is pointless - please STOP !

Kind Regards
Scott C





Thursday, April 9, 2015

Arduino BeatBox

Create your very own Arduino BeatBox !

Home-made capacitive touch sensors are used to trigger the MP3 drum sounds stored on the Grove Serial MP3 player. I have used a number of tricks to get the most out of this module, and I was quite impressed on how well it did. Over 130 sounds were loaded onto the SDHC card. Most were drum sounds, but I added some farm animal noises to provide an extra element of surprise and entertainment. You can put any sounds you want on the module and play them back quickly. We'll put the Grove Serial MP3 module through it's paces and make it into a neat little BeatBox !!


Key learning objectives

  • How to make your own beatbox
  • How to make capacitive drum pad sensors without using resistors
  • How to speed up Arduino's Analog readings for better performance
  • How to generate random numbers on your Arduino


Parts Required:

Making the drum pads



 
 

Fritzing Sketch


 


 
 

Grove Connections


 


 
 

Grove Connections (without base shield)


 


 
 

Arduino Sketch


 
  1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239

/* =================================================================================================
      Project: Arduino Beatbox
       Author: Scott C
      Created: 9th April 2015
  Arduino IDE: 1.6.2
      Website: http://arduinobasics.blogspot.com/p/arduino-basics-projects-page.html
  Description: This project uses home made capacitive sensors to trigger over 130 MP3 sounds
               on the Grove Serial MP3 player. 
               
               The ADCTouch library is used to eliminate the resistors from the Capacitive sensing circuit. 
               The code used for capacitive sensing was adapted from the ADCTouch library example sketches. 
               You can find the ADCTouch library and relevant example code here:
               http://playground.arduino.cc/Code/ADCTouch
               
               "Advanced Arduino ADC" is used to improve the analogRead() speed, and enhance the
               drum pad or capacitive sensor response time. The Advanced Arduino ADC code 
               was adapted from this site:
               http://www.microsmart.co.za/technical/2014/03/01/advanced-arduino-adc/
               
               
=================================================================================================== */
  #include <ADCTouch.h>
  #include <SoftwareSerial.h>
  
  
  //Global variables
  //===================================================================================================
  int potPin = A4; //Grove Sliding potentiometer is connected to Analog Pin 4
  int potVal = 0;
  byte mp3Vol = 0; //Variable used to control the volume of the MP3 player
  byte oldVol = 0;
  
  int buttonPin = 5; //Grove Button is connected to Digital Pin 5
  int buttonStatus = 0;
  
  byte SongNum[4] = {0x01,0x02,0x03,0x04}; //The first 4 songs will be assigned to the drum pads upon initialisation
  byte numOfSongs = 130; //Total number of MP3 songs/sounds loaded onto the SDHC card
  
  long randNumber; //Variable used to hold the random number - used to randomise the sounds.
  
  int ledState[4]; //Used to keep track of the status of all LEDs (on or off)
  int counter = 0;
  
  SoftwareSerial mp3(3, 4); // The Grove MP3 Player is connected to Arduino digital Pin 3 and 4 (Serial communication)
       
  int ref0, ref1, ref2, ref3; //reference values to remove offset
  int threshold = 100;
      
  // Define the ADC prescalers
  const unsigned char PS_64 = (1 << ADPS2) | (1 << ADPS1);
  const unsigned char PS_128 = (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
  
  
  
  //Setup()
  //===================================================================================================
  void setup(){
    //Initialise the Grove MP3 Module
    delay(2500); //Allow the MP3 module to power up
    mp3.begin(9600); //Begin Serial communication with the MP3 module
    setPlayMode(0x00);                        //0x00 = Single song - played once ie. not repeated. (default)
    
    //Define the Grove Button as an INPUT
    pinMode(buttonPin, INPUT);
    
    //Define the 4 LED Pins as OUTPUTs
    pinMode(8, OUTPUT); //Green LED
    pinMode(9, OUTPUT); //Blue LED
    pinMode(10, OUTPUT); //Red LED
    pinMode(11, OUTPUT); //Yellow LED
    
    //Make sure each LED is OFF, and store the state of the LED into a variable.
    for(int i=8;i<12;i++){
      digitalWrite(i, LOW);
      ledState[i-8]=0;
    } 
    
    //Double our clock speed from 125 kHz to 250 kHz
    ADCSRA &= ~PS_128;   // set up the ADC
    ADCSRA |= PS_64;    // set our own prescaler to 64
    
    //Create reference values to account for the capacitance of each pad.
    ref0 = ADCTouch.read(A0, 500);
    ref1 = ADCTouch.read(A1, 500); //Take 500 readings
    ref2 = ADCTouch.read(A2, 500);
    ref3 = ADCTouch.read(A3, 500);
    
     //This helps to randomise the drum pads.
     randomSeed(analogRead(0));
  }
  
  
  
  // Loop()
  //===================================================================================================
  void loop(){
     
    //Take a reading from the Grove Sliding Potentiometer, and set volume accordingly
    potVal = analogRead(potPin);
    mp3Vol = map(potVal, 0, 1023, 0,31); // Convert the potentometer reading (0 - 1023) to fit within the MP3 player's Volume range (0 - 31)
    if((mp3Vol>(oldVol+1))|(mp3Vol<(oldVol-1))){ // Only make a change to the Volume on the Grove MP3 player when the potentiometer value changes
      oldVol = mp3Vol;
      setVolume(mp3Vol);
      delay(10); // This delay is necessary with Serial communication to MP3 player
    }
    
    //Take a reading from the Pin attached to the Grove Button. If pressed, randomise the MP3 songs/sounds for each drum pad, and make the LEDs blink randomly.
    buttonStatus = digitalRead(buttonPin);
    if(buttonStatus==HIGH){
      SongNum[0]=randomSongChooser(1, 30);
      SongNum[1]=randomSongChooser(31, 60);
      SongNum[2]=randomSongChooser(61, 86);
      SongNum[3]=randomSongChooser(87, (int)numOfSongs);
      randomLEDBlink();
    }
    
    //Get the capacitive readings from each drum pad: 50 readings are taken from each pad. (default is 100)
    int value0 = ADCTouch.read(A0,50); // Green drum pad
    int value1 = ADCTouch.read(A1,50); // Blue drum pad
    int value2 = ADCTouch.read(A2,50); // Red drum pad
    int value3 = ADCTouch.read(A3,50); // Yellow drum pad
    
    //Remove the offset to account for the baseline capacitance of each pad.
    value0 -= ref0;       
    value1 -= ref1;
    value2 -= ref2;
    value3 -= ref3;
    
    
    //If any of the values exceed the designated threshold, then play the song/sound associated with that drum pad.
    //The associated LED will stay on for the whole time the drum pad is pressed, providing the value remains above the threshold.
    //The LED will turn off when the pad is not being touched or pressed.
    if(value0>threshold){
      digitalWrite(8, HIGH);
      playSong(00,SongNum[0]);
    }else{
      digitalWrite(8,LOW);
    }
    
    if(value1>threshold){
      digitalWrite(9, HIGH);
      playSong(00,SongNum[1]);
    }else{
      digitalWrite(9,LOW);
    }
    
    if(value2>threshold){
      digitalWrite(10, HIGH);
      playSong(00,SongNum[2]);
    }else{
      digitalWrite(10,LOW);
    }
    
    if(value3>threshold){
      digitalWrite(11, HIGH);
      playSong(00,SongNum[3]);
    }else{
      digitalWrite(11,LOW);
    }
  }
      
   
  // writeToMP3:
  // a generic function that simplifies each of the methods used to control the Grove MP3 Player
  //===================================================================================================
  void writeToMP3(byte MsgLEN, byte A, byte B, byte C, byte D, byte E, byte F){
    byte codeMsg[] = {MsgLEN, A,B,C,D,E,F};
    mp3.write(0x7E); //Start Code for every command = 0x7E
    for(byte i = 0; i<MsgLEN+1; i++){
      mp3.write(codeMsg[i]); //Send the rest of the command to the GROVE MP3 player
    }
  }
  
  
  //setPlayMode: defines how each song is to be played
  //===================================================================================================
  void setPlayMode(byte playMode){
    /* playMode options:
          0x00 = Single song - played only once ie. not repeated.  (default)
          0x01 = Single song - cycled ie. repeats over and over.
          0x02 = All songs - cycled 
          0x03 = play songs randomly                                           */
    writeToMP3(0x03, 0xA9, playMode, 0x7E, 0x00, 0x00, 0x00);  
  }
  
  
  //playSong: tells the Grove MP3 player to play the song/sound, and also which song/sound to play
  //===================================================================================================
  void playSong(byte songHbyte, byte songLbyte){
    writeToMP3(0x04, 0xA0, songHbyte, songLbyte, 0x7E, 0x00, 0x00);            
    delay(100);
  }
  
  
  //setVolume: changes the Grove MP3 player's volume to the designated level (0 to 31)
  //===================================================================================================
  void setVolume(byte Volume){
    byte tempVol = constrain(Volume, 0, 31); //Volume range = 00 (muted) to 31 (max volume)
    writeToMP3(0x03, 0xA7, tempVol, 0x7E, 0x00, 0x00, 0x00); 
  }
  
  
  //randomSongChooser: chooses a random song to play. The range of songs to choose from
  //is limited and defined by the startSong and endSong parameters.
  //===================================================================================================
  byte randomSongChooser(int startSong, int endSong){
    randNumber = random(startSong, endSong);
    return((byte) randNumber);
  }
  
  
  //randomLEDBlink: makes each LED blink randomly. The LEDs are attached to digital pins 8 to 12.
  //===================================================================================================
  void randomLEDBlink(){
   counter=8;
   for(int i=0; i<40; i++){
     int x = constrain((int)random(8,12),8,12);
     toggleLED(x);
     delay(random(50,100-i));
   }
     
    for(int i=8;i<12;i++){
      digitalWrite(i, HIGH);
    }
    delay(1000);
    for(int i=8;i<12;i++){
      digitalWrite(i, LOW);
      ledState[i-8]=0;
    }
  }
  
  
  //toggleLED: is used by the randomLEDBlink method to turn each LED on and off (randomly).
  //===================================================================================================
  void toggleLED(int pinNum){
    ledState[pinNum-8]= !ledState[pinNum-8];
    digitalWrite(pinNum, ledState[pinNum-8]);
  }


 

Arduino Code Discussion

You can see from the Arduino code above, that it uses the ADCTouch library. This library was chosen over the Capacitive Sensing Library to eliminate the need for a high value resistor which are commonly found in Capacitive Sensing projects).
 
To increase the speed of the Analog readings, I utilised one of the "Advanced Arduino ADC" techniques described by Guy van den Berg on this Microsmart website.
 
The readings are increased by modifying the Arduino's ADC clock speed from 125kHz to 250 kHz. I did notice an overall better response time with this modification. However, the Grove Serial MP3 player is limited by it's inability to play more than one song or sound at a time. This means that if you hit another drum pad while the current sound is playing, it will stop playing the current sound, and then play the selected sound. The speed at which it can perform this task was quite impressive. In fact it was much better than I thought it would be. But if you are looking for polyphonic playability, you will be dissapointed.
 
This Serial MP3 module makes use of a high quality MP3 audio chip known as the "WT5001". Therefore, you should be able to get some additional features and functionality from this document. Plus you may find some extra useful info from the Seeedstudio wiki. I have re-used some code from the Arduino Boombox tutorial... you will find extra Grove Serial MP3 functions on that page.
 
I will warn you... the Grove Serial MP3 player can play WAV files, however for some reason it would not play many of the sound files in this format. Once the sounds were converted to the MP3 format, I did not look back. So if you decide to take on this project, make sure your sound files are in MP3 format, you'll have a much better outcome.
 
I decided to introduce a random sound selection for each drum pad to extend the novelty of this instrument, which meant that I had to come up with a fancy way to illuminate the LEDs. I demonstrated some of my other LED sequences on my instagram account. I sometimes use instagram to show my work in progress.
 
Have a look at the video below to see this project in action, and putting the Grove Serial MP3 player through it's paces.
 

The Video


 


First there was the Arduino Boombox, and now we have the Arduino Beatbox..... who knows what will come next !
 
Whenever I create a new project, I like to improve my Arduino knowledge. Sometimes it takes me into some rather complicated topics. There is a lot I do not know about Arduino, but I am enjoying the journey. I hope you are too !! Please Google plus one this post if it helped you in any way. These tutorials are free, which means I survive on feedback and plus ones... all you have to do is just scroll a little bit more and click that button :)

 
 



If you like this page, please do me a favour and show your appreciation :

 
Visit my ArduinoBasics Google + page.
Follow me on Twitter by looking for ScottC @ArduinoBasics.
I can also be found on Pinterest and Instagram.
Have a look at my videos on my YouTube channel.


 
 

 
 
 



However, if you do not have a google profile...
Feel free to share this page with your friends in any way you see fit.