Introduction: How to Build an Air Guitar With Arduino, Aka the AIRduino Guitar

The idea here is to build a wearable virtual guitar that is to be controlled with two hands much like playing Air Guitar. It has been created and prototyped during a two weeks project at ChalmersUniversity (Sweden) for a Physical Computing class.

The aim is to get the feeling of playing a real guitar. The AIRduino Guitar is made of one glove and one stick. The glove is used to set the tone and the stick to trigger the sound.

To perform such trick, we used an accelerometer and an ultra-sonic sensor (see Step 1 for concept description).

Take a look at the video demo to get a more precise idea of how it works, and get to work to build your own!


The AIRduino Team:

David Fournier, Jean-Louis Giordano, Monireh Sanaei, Maziar Shelbaf and Gustav Sohtell.

Step 1: Concept Description

The Air Guitar is supposed to work as a right-handed guitar.

The guitar controller is divided in two parts, left-hand controller and right-hand controller.
By left-hand controller the player can bend his fingers and press the glove to change the pitch of the tone.

The right-hand controller is represented by a stick which has to be shaken to trigger the sound of the air-guitar.

Player can also change the distance between right hand and left hand in order to pitch the tones, simulating the different frets on the guitar neck.

To perform such tricks, the main components are an accelerometer to "feel" the stick shake, an hacked ultra-sonic sensor to measure the distance between the right hand and the stick, and conductive fabric to build the glove.

All in all, it is an fairly easy to build toy. The only tricky part would be the ultra-sonic sensor hack which requires some dexterity. You will need some basic electronic skills to understand the instructions, and also to find out what you did wrong when you messed something up and the guitar doesn't work in the end. We have been there. :-)

Step 2: Shopping List

Here is a list of what you need to build your own AIRduino Guitar:

1. Wires: unfortunately a lot for this prototype version. They have been used to connect the two gloves and the Arduino parts together. Feel free to improve this part of the design by making it wireless!

2. Accelerometer: used in the stick in your right hand to detect the shaking. We used a three-axis accellerometer, but a one-axis is enough

3. Ultrasonic sensor: used to measure the distance between both hands of the player, we used Parallax #28015

4. Conductive and Stretch fabric: to build the glove,

5. Arduino: the core of the Guitar that handles everything. An Arduino Diecimila works fine.

6. Potentiometers: to adjust some settings, A potentiometer with a max of anything from 1KOhm-1MOhm is ok.

7. Hot melt glue: a convenient way to hold things together,

8. 3.5 mm female jack: used for the audio output,

9. Classic electronic stuff: Resistors (10k), capacitor(10uF), LEDs and some kind of power supply for the arduino. (A 9V battery is just fine).

Step 3: Schematics

Here are the electronic schematics for the AIRduino Guitar.

As you can see, it is pretty easy to understand and therefore also to build.

Look at the image if you want an idea of which component goes where. As you probably understand, this is no to scale in any way. The cables are much longer than shown in the schematic.

You might also have noticed that the emitter of the ultra-sonic sensor is on the stick and the receiver is on the left hand. That is the tricky part I have mentioned earlier: You must unsolder the ultra-sonic emitter from the ultra-sonic sensor unit in order to separate it from the sensor board.

More about that in later steps. Now let's get to work!

Step 4: Building the Glove

The glove contains one ultra-sonic receiver and four buttons. That's it!

The ultra-sonic receiver is located in the black box visible on some of the pictures below.
The glove has one large area which is just connected to ground on the Arduino board. When a finger is pressed against the palm a connection between the conductive fabric on the finger and the palm is created.

Below are picture of two different glove models. One has detachable fingers, which allows both players with very small and very large hands. The other model is sewed right on to a standard glove. I'd recommend the second version, it is easier to build, and easier to put on.

Step 5: Code

Here is the Arduino code required:

The real-time sound generation part is taken from this great tutorial.

------------------------------------------------------
// An array containing the waveform
// of a guitar sound
char waveform[] =
{125, 148, 171, 194, 209, 230, 252, 255,
253, 244, 235, 223, 207, 184, 169, 167,
163, 158, 146, 131, 126, 129, 134, 127,
105, 80, 58, 51,38, 22, 12,  2, 10, 35,
58, 75, 89, 103, 120, 141, 150, 148, 145,
144, 140, 129, 116, 105, 95, 86, 75, 72,
73, 76, 88, 103, 117, 121, 120, 115, 120,
143, 159, 162, 156, 155, 163, 184, 202,
214, 215, 211, 213, 212, 205, 196, 182,
162, 142, 118, 99, 84, 68, 54, 40, 28,
19, 10,  7,  0,  0,  5,  9, 14, 21, 33,
49, 59, 65, 75, 92, 110};

// We use this waveform to change the
// volume of the output
char waveformVolume[] =
{125, 148, 171, 194, 209, 230, 252, 255,
253, 244, 235, 223, 207, 184, 169, 167,
163, 158, 146, 131, 126, 129, 134, 127,
105, 80, 58, 51,38, 22, 12,  2, 10, 35,
58, 75, 89, 103, 120, 141, 150, 148, 145,
144, 140, 129, 116, 105, 95, 86, 75, 72,
73, 76, 88, 103, 117, 121, 120, 115, 120,
143, 159, 162, 156, 155, 163, 184, 202,
214, 215, 211, 213, 212, 205, 196, 182,
162, 142, 118, 99, 84, 68, 54, 40, 28,
19, 10,  7,  0,  0,  5,  9, 14, 21, 33,
49, 59, 65, 75, 92, 110};
// An array used as a buffer to avoid
// erroneous punctual distance
// measurements
unsigned int distance_buffer[] = {16000,
16000, 16000, 16000, 16000, 16000, 16000,
16000, 16000, 16000, 16000, 16000, 16000,
16000, 16000, 16000};

const int distance_length = 3;
int distance_index = 0;

// The overflow values for 2 octaves
int frequencies[] = { 39, 42, 44, 47,
50, 52, 56, 59, 63, 66, 70, 74, 79,
84, 89, 94, 100, 105, 112, 118, 126,
133, 141, 149};

// Initial pitch
int pitch = 160;

// Initial volume and acceleration
// parameter
int lastAcc = 0;
float volume = 0;

//audio playback on pin 3
byte speakerpin = 3;

//index variable for position in
//waveform
volatile byte waveindex = 0
volatile byte currentvalue = 0;

// Pin used for ultra-sonic sensor
const int pingPin = 7;

// Pins for the potentiometers
const int sustainPin = 1;
const int sensitivityPin = 2;

// Pins for each finger of the left
// hand
const int finger1 = 9;
const int finger2 = 10;
const int finger3 = 11;
const int finger4 = 12;

int fingerValue = 0;

long duration, inches, cm;

void setup() {

pinMode(3,OUTPUT); //Speaker on pin 3

pinMode(finger1,INPUT);
pinMode(finger2,INPUT);
pinMode(finger3,INPUT);
pinMode(finger4,INPUT);


/**************************
    PWM audio configuration
****************************/
//set Timer2 to fast PWM mode
//(doubles PWM frequency)
bitSet(TCCR2A, WGM21);
bitSet(TCCR2B, CS20);
bitClear(TCCR2B, CS21);
bitClear(TCCR2B, CS22);

//enable interrupts now that registers
// have been set
sei();


/*************************
Timer 1 interrupt configuration
*************************/
//disable interrupts while
// registers are configured
cli();

/* Normal port operation, pins disconnected
from timer operation (breaking pwm) */
bitClear(TCCR1A, COM1A1);
bitClear(TCCR1A, COM1A1);
bitClear(TCCR1A, COM1A1);
bitClear(TCCR1A, COM1A1);

/* Mode 4, CTC with TOP set by register
OCR1A. Allows us to set variable timing for
the interrupt by writing new values to
OCR1A. */
bitClear(TCCR1A, WGM10);
bitClear(TCCR1A, WGM11);
bitSet(TCCR1B, WGM12);
bitClear(TCCR1B, WGM13);

/* set the clock prescaler to /8.  */
bitClear(TCCR1B, CS10);
bitSet(TCCR1B, CS11);
bitClear(TCCR1B, CS12);

/* Disable Force Output Compare for
Channels A and B. */
bitClear(TCCR1C, FOC1A);
bitClear(TCCR1C, FOC1B);

/* Initializes Output Compare
Register A at 160 to set the
initial pitch */
OCR1A = 160;

//disable input capture interrupt
bitClear(TIMSK1, ICIE1);
//disable Output
//Compare B Match Interrupt
bitClear(TIMSK1, OCIE1B);
//enable Output
//Compare A Match Interrupt
bitSet(TIMSK1, OCIE1A);
//disable Overflow Interrupt
bitClear(TIMSK1, TOIE1);

// enable interrupts now that
// registers have been set
sei();
}

// Timer overflow handler
ISR(TIMER1_COMPA_vect) {

 /* timer1 ISR.  Every time it
 is called it sets speakerpin to the
 next value in waveform[]. Frequency
 modulation is done by changing the
 timing between successive calls of
 this  function, e.g. for a 1KHz tone,
 set the  timing so that it runs
 through waveform[] 1000 times
 a second. */

 // reset waveindex if it has reached
 // the end of the array

 if (waveindex > 102) {
  waveindex = 0;
 }

 //Set the output value
 if (volume > 0.03) {
  analogWrite(speakerpin,
   waveformVolume[waveindex]);
 }
 waveindex++;

 // Update the pitch
 OCR1A = pitch;



void loop()
{
 // Desactivate interputs, send a ping
 // message and wait for the answer.
 cli();
 pinMode(pingPin, OUTPUT);
 digitalWrite(pingPin, LOW);
 delayMicroseconds(2);
 digitalWrite(pingPin, HIGH);
 delayMicroseconds(5);
 digitalWrite(pingPin, LOW);
 duration = pulseIn(pingPin, HIGH, 2000);
 sei();
 // convert the time into a distance
 // in centimetres
 // and store in buffer
 distance_buffer[distance_index++
  % distance_length] = duration / 20;

 //Find in the buffer the shortest
 // distance measured
 cm = 16000;
 for(int i = 0; i < distance_length; i++) {
  cm = min(cm, distance_buffer[i]);
 }

 // Check which fingers are pressed
 fingerValue = 5;
 if(!digitalRead(finger4)){
  fingerValue = 4;
 }
 if(!digitalRead(finger3)){
  fingerValue = 3;
 }
 if(!digitalRead(finger2)){
  fingerValue = 2;
 }
 if(!digitalRead(finger1)){
  fingerValue = 1;
 }

 // Update the sustain and
 // sensitivity values
 float sustain =
 map(analogRead(sustainPin), 0,
  1024, 101, 130) / 100.0;
 int sensitivity =
    map(analogRead(sensitivityPin),
    0, 1024, 100, 200);

 // Update the volume
 volume = volume / sustain;
 if (volume < 0) {
  volume = 0;
 }

 // Check the accelerometer
 int acc = analogRead(0);
 int accDiff = lastAcc - acc;

 // Update the volume value
 if (accDiff > 5 * (200 - sensitivity)) {
  volume += (float)
   pow(accDiff,
       sensitivity / 100.0) / 50000;
 }
 lastAcc = acc;

 // Check that volume is not higher than 1
 if(volume > .95) {
  volume = .95;
 }

 // Update the volume in the waveform
 for(int i = 0; i <= 102; i++) {
  waveformVolume[i] =
   ((waveform[i] - 127) * volume) + 127;
 }

 // Set the pitch according to the distance
 // between the two hands and the
 // fingers pressed
 if(cm < 102 && cm > 0) {
  if(cm > 30) {
   pitch = frequencies[7 +
    (((cm - 30) / 24) * 4 + fingerValue - 1)];
  }else{
   pitch = map(cm, 0, 30, 39, 79);
  }
 }else{
  pitch = frequencies[7 +
   (((102 - 30) / 24) * 4 + fingerValue - 1)];
 }

 // Delay to avoid bouncing signals
 delay(50);
}

------------------------------------------------------


Arduino Contest

Participated in the
Arduino Contest