TOM BEDFORD: PART 2: 6 WEEK ARDUINO RAVIOMETER ENTERTAINMENT SYSTEM

After being introduced to Arduino and the musical and led mini project, I decided to progress on along the same lines, combining Led’s and music with a more accurate reaction and interactive element.

I first researched into higher quality audio systems, looking at:

https://learn.adafruit.com/adafruit-microphone-amplifier-breakout/measuring-sound-levels

http://www.cui.com/product/resource/cma-4544pf-w.pdf

After researching into the compatible components that I could use I decided to use these components working around the idea of the neo pixel rings making a circle around one speaker, I later changed this as the neopixel strips turned out to be more expensive than anticipated as well as the decision to use two speakers for better sound quality.

https://www.adafruit.com/products/1768

A higher quality ultrasonic distance sensor for accurate distance evaluation.

https://docs.google.com/document/d/1Y-yZnNhMYy7rwhAgyL_pfa39RsB-x2qR4vP8saG73rE/edit?pli=1

A speaker and amp that are compatible with 20 W power ratings.

http://www.adafruit.com/products/1732

http://www.adafruit.com/products/1752

I also wanted to integrate an interactive side to the system where it would react to peoples presence using the ultrasonic distance sensor. I decided to use a subwoofer bass valve into the system, that when people stand in front of the system the subwoofer valve will open allowing more air to go into the speaker housing making the music bassier.

http://www.instructables.com/id/Simple-Arduino-and-HC-SR04-Example/

http://www.soundonsound.com/sos/apr07/articles/subwoofers.htm

I also looked at more advanced code for creating a VU meter using neopixels

https://learn.adafruit.com/led-ampli-tie/overview

I first started the hardware hook-up with getting the speaker and amp working together.

https://www.youtube.com/watch?v=XBwBYbQ_JL8&list=PL4nvy4fQXiauCLNZb_O5t6Jg9lrkFdzvS&index=17

I revisited the servo sweep code we looked at near the beginning of Arduino.

https://www.youtube.com/watch?v=MTUO_7ZdcAs&list=PL4nvy4fQXiauCLNZb_O5t6Jg9lrkFdzvS&index=18

I next got the ultrasonic distance sensor reading of values with the example code.

https://www.youtube.com/watch?v=-Z8UzbInG-I&list=PL4nvy4fQXiauCLNZb_O5t6Jg9lrkFdzvS&index=19

Finally I combined the servo and ultrasonic distance sensor getting the servo to sweep between 0 and 90 degrees with threshold values.

https://www.youtube.com/watch?v=XHosHZv758M&list=PL4nvy4fQXiauCLNZb_O5t6Jg9lrkFdzvS&index=20

Throughout the next few stages there are several iterations where I adjust settings with the gain and code hacked from the adafruit ‘amliptie’ code.

https://www.youtube.com/watch?v=2AvQqJmZlxg&list=PL4nvy4fQXiauCLNZb_O5t6Jg9lrkFdzvS&index=21

https://www.youtube.com/watch?v=zYsP0MNDb-c&list=PL4nvy4fQXiauCLNZb_O5t6Jg9lrkFdzvS&index=22

Trying to get the best reaction from the VU meter.

I next properly linked up the speaker and amp hardware with a potentiometer for volume and capacitor for current control.

https://www.youtube.com/watch?v=56XG9qV74Dg&list=PL4nvy4fQXiauCLNZb_O5t6Jg9lrkFdzvS&index=23

Finally after playing with the settings the Vu meter started to look accurate with the music.

https://www.youtube.com/watch?v=3PX8wZV77tQ&list=PL4nvy4fQXiauCLNZb_O5t6Jg9lrkFdzvS&index=24

I next revisited the LDR code to get the LDR working with threshold values to, in the end act as a switch.

https://www.youtube.com/watch?v=EvRkBLV8FxQ&list=PL4nvy4fQXiauCLNZb_O5t6Jg9lrkFdzvS&index=25

I then used a toggle switch to work with simple code for an on/off reaction with an led.

https://www.youtube.com/watch?v=eNQzuW-HuIo&index=27&list=PL4nvy4fQXiauCLNZb_O5t6Jg9lrkFdzvS

Even more adjustment to VU meter code…

https://www.youtube.com/watch?v=0ppZkc2IfuE&index=26&list=PL4nvy4fQXiauCLNZb_O5t6Jg9lrkFdzvS

https://www.youtube.com/watch?v=kMB2pMn6S84&index=28&list=PL4nvy4fQXiauCLNZb_O5t6Jg9lrkFdzvS

And finally after some forum posting and searching I managed to solve my mirroring troubles by simply connecting the two pixel strips to the same pin.

https://www.youtube.com/watch?v=1AmxXJ806AY&index=29&list=PL4nvy4fQXiauCLNZb_O5t6Jg9lrkFdzvS

FINAL STAGES PUTTING TOGETHER THE SEPARATE CODES

Part 1 of combined code – Switch and LDR and working

https://www.youtube.com/watch?v=kj3USdy_Drs&index=30&list=PL4nvy4fQXiauCLNZb_O5t6Jg9lrkFdzvS

Part 2 of combined code – Switch, LDR, Distance sensor and Servo working together

https://www.youtube.com/watch?v=LiO52gxWILs&index=31&list=PL4nvy4fQXiauCLNZb_O5t6Jg9lrkFdzvS

With part 3 of combing the code I had some issues with the vu meter reacting oddly with the servo, I first thought this was down to power, but it turns out it was a problem with the delay in the code confusing the vu meter code.

https://www.youtube.com/watch?v=I4wckozvHMc&list=PL4nvy4fQXiauCLNZb_O5t6Jg9lrkFdzvS&index=32

I also built the speaker housing out of 6mm acrylic and line bent it to shape to form the housing.

https://www.youtube.com/watch?v=t44BiOIbuIk&index=33&list=PL4nvy4fQXiauCLNZb_O5t6Jg9lrkFdzvS

After posting in adafruit and Arduino forum for help, I managed to bug fix the issues with the vu meter and servo reacting oddly, by using a different servo library specially made for working with neopixels and also I had to remove all delays from the code which made the servo reaction a bit jumpy, a compromise.

Part 3 of combined code WORKING – Switch, LDR, DS and Servo with Mic and Neopixels

https://www.youtube.com/watch?v=RivxCf-4Avc&list=PL4nvy4fQXiauCLNZb_O5t6Jg9lrkFdzvS&index=34

Finally I integrated the hardware into the speaker housing and hey presto!

This video shows all the features.

https://www.youtube.com/watch?v=G_Hpg-4ecM4&list=PL4nvy4fQXiauCLNZb_O5t6Jg9lrkFdzvS&index=35

Finally just to show the accuracy of the VU meter reaction:

https://www.youtube.com/watch?v=XRHSmmGLBMM&list=PL4nvy4fQXiauCLNZb_O5t6Jg9lrkFdzvS&index=36

I really enjoyed second half of the project with more time to spend refining details and making more of a resolved prototype that I can now keep.

Thanks for reading 🙂

FINAL CODE:

#include <Adafruit_TiCoServo.h>    // initialising servo library that can be used with neopixel
int buttonpin = 12;     // toggle switch connected to pin 12
int lightPin = 1;       // LDR connected to pin A1
int ledpin = 6;         // Led 1 connected to pin 6
int ledpin2 = 13;       // Led 2 connected to pin 13
int state;              // Variable to hold whether the switch is on or off (HIGH or LOW)

//part 2 code

int trigPin = 10;       // Trigger pin for ultrasonic distance sensor
int echoPin = 11;       // Trigger pin for ultrasonic distance sensor
int mini = 20;          // Threshhold for mimimum distance
int maxi = 200;         // Threshhold for maximum distance
int pos = 0;            // Home position for servo to go too (0)
Adafruit_TiCoServo myservo;   //Initialising servo

//part 3

#include <Adafruit_NeoPixel.h>

#define N_PIXELS  15  // Number of pixels in strip
#define MIC_PIN   A0  // Microphone is attached to A0
#define LED_PIN    5  // NeoPixel LED strands are connected to pin 5
#define DC_OFFSET  0  // DC offset in mic signal (0)
#define NOISE     20  //  Variable to to filter out unwanted noise in mic signal
#define SAMPLES   60  // Length of buffer/ number of audio samples taken
#define TOP       (N_PIXELS + 2) // Defining where the neo pixel ends – Allow dot to go off scale to create more fluent effect
#define PEAK_FALL 4  // Rate at which the light drops between the pixels in the strip

int Sound = 0;
byte
peak      = 0,      // Peak for falling dot
dotCount  = 0,      // counter for delaying dot-falling speed
volCount  = 0;      // counter for storing past volume data
int
vol[SAMPLES],       // Collection of the previous volume samples
lvl       = 10,     // Current “dampened” audio level
minLvlAvg = 20,   // For  adjustment of graph low to high
maxLvlAvg = 550;    // For  adjustment of graph low to high
Adafruit_NeoPixel
strip = Adafruit_NeoPixel (N_PIXELS, LED_PIN  , NEO_GRB + NEO_KHZ800);   // Stating the variables within the strip

void setup()

{
pinMode(buttonpin, INPUT);   // Stating that the toggle switch is an INPUT
pinMode(ledpin, OUTPUT);     // Stating that led 1 is an OUTPUT
pinMode(ledpin2, OUTPUT);    // Stating that led 2 is an OUTPUT
Serial.begin(9600);          // Serial begin to get read off’s of whats happening in the rest of the code

pinMode(trigPin, OUTPUT);     // Stating that the trigger pin outputs the signal
pinMode(echoPin, INPUT);      // Stating that the echo pin collects the signal from the bounce back
myservo.attach(9);            // Stating that the servo is attached to pin 9

memset(vol, 0, sizeof(vol));
strip.begin();              // Start of neopixel strip code
}

void loop()
{
state = digitalRead(buttonpin);              // Stating that ‘state’ is a read of the button pin HIGH or LOW
int lightLevel = analogRead(lightPin);       // Variable for the state of the LDR reading the light in the room
if (state == HIGH)                           // if switch is on
{
digitalWrite(ledpin2,HIGH);                // turn led 2 on
}
else                                         // if not
{
digitalWrite(ledpin2,LOW);                // keep led 2 off
}
if ((state == HIGH)&&( lightLevel <= 250))   // if led is on and the light level in the room is less than 250
{
digitalWrite(ledpin,HIGH);                 // turn led 1 on
}
else                                         // if not
{
digitalWrite(ledpin,LOW);                  // keep led 1 off
}

//part 2

long duration, distance;
digitalWrite(trigPin, LOW);  // Set triggerpin to low
delayMicroseconds(2);        // Wait 2 microseconds
digitalWrite(trigPin, HIGH); // Set triggerpin to high
delayMicroseconds(10);       // Wait 10 microseconds
digitalWrite(trigPin, LOW);  // Set triggerpin to low
duration = pulseIn(echoPin, HIGH);  // Duration equals pulse measured from echo pin
distance = (duration/2) / 29.1;     // Distance = speed (of pulse) x time (to return)
Serial.print(distance);
Serial.println(” cm”);             // Print distance in cm
if ((lightLevel >= 250) && (distance >= mini) && ( distance <= maxi))   // if the lightlevel is less than 250 and the distance is between the minimum and maximum thresholds
{
Serial.println(“open”);             // print servo ”open”
myservo.write(90);               // move servo to 90 degrees

}
else if ((distance < mini)||(distance > maxi)) // If distance is outside this range
{
Serial.println(“close”);        // print servo ”closed”
myservo.write(0);                // move servo to 0 position

}

uint8_t  i;
uint16_t minLvl, maxLvl;
int      n, height;            // n for height

n   = analogRead(MIC_PIN);                        // Raw reading from microphone
n   = abs(n – 200 – DC_OFFSET); // Center DC offset to 0
n   = (n <= NOISE) ? 0 : (n – NOISE);             // Remove unwanted noise
lvl = ((lvl * 7) + n) >> 3;    // “Dampens” the reading else the lights look twitchy

// Calculate VU heights based on the dynamic min and max levels
height = TOP * (lvl – minLvlAvg) / (long)(maxLvlAvg – minLvlAvg);

if(height < 0L)       height = 0;      // Clip the height of the lights
else if(height > TOP) height = TOP;
if(height > peak)     peak   = height; // Keep ‘peak’ dot at top
// Color pixels using rainbow gradient colours
for(i=0; i<N_PIXELS; i++) {
if(i >= height)               strip.setPixelColor(i,   0,   0, 0);
else strip.setPixelColor(i,Wheel(map(i,0,strip.numPixels()-1,30,150)));

}

// Draw peak dot
if(peak > 0 && peak <= N_PIXELS-1) strip.setPixelColor(peak,Wheel(map(peak,0,strip.numPixels()-1,30,150)));

strip.show(); // Update strip

// Every few frames, make the peak pixel drop by 1: gives more realistic volume effect

if(++dotCount >= PEAK_FALL) { //fall rate

if(peak > 0) peak–;
dotCount = 0;
}

vol[volCount] = n;                      // Save sample for dynamic leveling
if(++volCount >= SAMPLES) volCount = 0; // Advance/rollover sample counter

// Get volume range of prior frames
minLvl = maxLvl = vol[0];
for(i=1; i<SAMPLES; i++) {
if(vol[i] < minLvl)      minLvl = vol[i];
else if(vol[i] > maxLvl) maxLvl = vol[i];
}

if((maxLvl – minLvl) < TOP) maxLvl = minLvl + TOP;
minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6; // Dampen min/max levels
maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6;

}

//  value 0 to 255 to get a rerquired colour
// The colors are a transition RGB back to R
uint32_t Wheel(byte WheelPos) {
if(WheelPos < 85) {
return strip.Color(WheelPos * 3, 255 – WheelPos * 3, 0);
} else if(WheelPos < 170) {
WheelPos -= 85;
return strip.Color(255 – WheelPos * 3, 0, WheelPos * 3);
} else {
WheelPos -= 170;
return strip.Color(0, WheelPos * 3, 255 – WheelPos * 3);
}
}

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s