Twitter

We (Lizzie) managed a huge feat in accomplishing pushing the data of the Arduino and sound sensor to Twitter. This created an additional layer of interactivity and in encouraging the individual to engage in monitoring the sound environment that they experience.

You can view the feed for the data we collected during setup, test and presentation here.

Advertisements

Tweet tweet

With the help of Will Skates writing a php script for me to send my values from the Arduino to, and send them on to twitter, it’s finally sending the sensor readings to twitter and flashing the lights.

I had to set this one up as a client to Will’s page instead of a server as before, but it’s all good.

// (Based on Ethernet's WebClient Example)

#include "WiFly.h"


#include "Credentials.h"


byte server[] = { 66, 249, 89, 104 }; // Google
int canConnect = 0;

int ledPin[] = {3,4,5};

int warningLevels[] = {200, 230, 270};
//int warningLevels[] = {20, 50, 100};

int sensorPin = A0;
int sensorValue = 0;

int readCount = 0;

int accumSound = 0;
int aveSound = 0;

int ledLit = 0;

//Client client(server, 80);

Client client(server, 80);

void setup() {
  
  Serial.begin(9600);

  WiFly.begin();
  
  Serial.println("associating");
  if (!WiFly.join(ssid, passphrase)) {
    Serial.println("Association failed.");
    while (1) {
      // Hang on failure.
    }
  }else{
    Serial.println("Association succeeded.");
  }  

  Serial.println("connecting...");

  if (client.connect()) {
    Serial.println("connected");
    canConnect = 1;
    client.println("GET /new?msg=openConn&pwd=(password) HTTP/1.1");
    client.println();
  } else {
    Serial.println("connection failed");
  }
  
}

void loop() {
  
  Serial.println("attempting request");
  
  
  delay(5000);
  
  //read sensor
  sensorValue = analogRead(sensorPin);
  //reread if values are not between our thresholds
  while(sensorValue == 0 || sensorValue > 350){
    sensorValue = analogRead(sensorPin); 
  }
  
  //add to readCount
  readCount ++;
          
  //add to accumulative sound
  accumSound += sensorValue;
  
  //work out average sound per minute
  aveSound = accumSound/readCount;
  
  //check against set levels
  for (int i=0; i<(sizeof(warningLevels)/2); i++){
    if (aveSound > warningLevels[i]){
      ledLit = i+1;
    }
  }
  
  //light LEDs
  for (int i=0; i<ledLit; i++){
    digitalWrite(ledPin[i], HIGH); 
  }
  
  client.stop();
  if (client.connect()) {
    String req = "GET /new?msg=";
    req += sensorValue;
    req += "&pwd=(password)";
    client.println(req);
    client.println();
  } else {
    Serial.println("connection failed");
  }

}

You can see the tweets here: https://twitter.com/decibear
Although now, being half 2am, I think it’s time for bed, which means no visualization, but we have a working blogject!

Code update so far

I’ve been working on the wifly stuff, and I’ve had some big issues, namely with the IP address, not being set from the router which is my phone. Finally fixed it now, so hopefully if I don’t change anything tonight on my phone or wiFly shield settings, it should work tomorrow!

This script still does the thing with the lights, but it also sends the information over the wiFly’s server, so I can read it on my phone while I’m out and about wearing the bear scarf!

The only real bug with this is that for some reason I can’t change the delay without messing up the client, so it’s currently reading every 10 ms rather than 30s, but I’m still working on that!

/*
 * Web Server
 *
 * (Based on Ethernet's WebServer Example)
 *
 * A simple web server that shows the value of the analog input pins.
 */

#include "WiFly.h"

char passphrase[] = "pass";
char ssid[] = "ssid";

int ledPin[] = {3,4,5};

int warningLevels[] = {200, 230, 270};
//int warningLevels[] = {20, 50, 100};

int sensorPin = A0;
int sensorValue = 0;

int readCount = 0;

int accumSound = 0;
int aveSound = 0;

int ledLit = 0;

Server server(80);

void setup() {
  
  for (int i=0; i<(sizeof(ledPin)/2); i++){
   pinMode(ledPin[i], OUTPUT); 
  }
  
  WiFly.begin();

  if (!WiFly.join(ssid, passphrase)) {
    while (1) {
      // Hang on failure.
    }
  }

  Serial.begin(9600);
  Serial.print("IP: ");
  Serial.println(WiFly.ip());
  
  server.begin();
}

void loop() {
  
  //read sensor
  sensorValue = analogRead(sensorPin);
  //reread if values are not between our thresholds
  while(sensorValue == 0 || sensorValue > 350){
    sensorValue = analogRead(sensorPin); 
  }
  
  //add to readCount
  readCount ++;
          
  //add to accumulative sound
  accumSound += sensorValue;
  
  //work out average sound per minute
  aveSound = accumSound/readCount;
  
  //check against set levels
  for (int i=0; i<(sizeof(warningLevels)/2); i++){
    if (aveSound > warningLevels[i]){
      ledLit = i+1;
    }
  }
  
  //light LEDs
  for (int i=0; i<ledLit; i++){
    digitalWrite(ledPin[i], HIGH); 
  }
  
  Client client = server.available();
  if (client) {
    // an http request ends with a blank line
    boolean current_line_is_blank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        // if we've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so we can send a reply
        if (c == '\n' && current_line_is_blank) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();
          
          //output the sensor values
          client.print("sensor value: ");
          client.print(sensorValue);
          client.print("<br/><br/>");
          
          //output the accumulative values
          client.print("You have had ");
          client.print(accumSound);
          client.print(" over ");
          client.print(readCount);
          client.print(" minutes.");
          client.println("<br />");
          
          //output the average values
          client.print("This is an average of ");
          client.print(aveSound);
          client.print(" per minute");
          client.println("<br/><br/>");
          
          //warn if over final level
          if (ledLit == 3){
           client.print("This is over your recommended allowance by ");
           client.print(aveSound - warningLevels[2]);
           client.print("<br/>"); 
          } else {
           client.print("This is under your recommended allowance by ");
           client.print(warningLevels[2] - aveSound);
           client.print("<br/>");
          }
          
          break;
        }
        if (c == '\n') {
          // we're starting a new line
          current_line_is_blank = true;
        } else if (c != '\r') {
          // we've gotten a character on the current line
          current_line_is_blank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(100);
    //delay(30000);
    client.stop();
  }
}

Now I’m at another stage where we could present if necessary, although I really would like to get it sending to twitter, or have some sort of visualization, or preferably both! I will keep working on it for a while, but I’ll need to get some sleep soonish as I barely slept last night, and tomorrow is the big day!

Sleepy-time

We were really hoping to be able to put the arduino to sleep and wake it up every 30 seconds or minute to scan for sound, then wake it up again, but it turns out this won’t be possible.

We thought it was a good idea in order to help make it more portable, in that the battery would last a lot longer, but according to everything I have managed to read about it, it seems that 8s is the longest you can put an arduino to sleep for without an external clock attached, which we have no hope of getting at this point.

Hopefully though, it won’t matter as we have already tested the system for 10 minutes off battery with a simple delay in, and it could have lasted even longer but I got bored!

Limits and averages

To find the levels of sound in the immediate environment, we have a sound sensor attached to LEDs to pinpoint when you have reached a level of sound in your environment that will become hazardous with extended exposure.

But what determines those levels is a (relative) understanding of how the sound meter relates to decibels.

This is a bit of a problem, because I am incredibly sucky at maths, but should be fairly simple to get a basic understanding of.

143
133
29
61
53
66
2
109
165
22
79
38
33

Omitting the 0 readouts, this is what the sensor gives us over a couple of seconds. The numbers are highly varied and show no clear graduation between low to high sound, perfectly indicative of how sound works, the sudden, incidental and unexpected is much documented in these readings, emphasised to a degree by having the sensor on its highest setting.

Translating these numbers is (at least for silly me) no small task, given that the power for each sound is increased for every three decibels. However, for the sake of time, I’ve left algebra for the most part to the side and worked out what the numbers mean against an android sound sensor with a decibel readout.

270 – 90dB

230 – 85dB

200 – 80 dB

140 – 70dB

80 – 60dB

These numbers are roughly accurate, and allow us to make better sense of what the sensor is giving us.

Considering decibels, we know that  85 decibels is safe for eight hour exposure per day times, and that with 91 decibels we are looking at a safe exposure time of only two hours. Referencing what we know of the three decibel incremental value, for every three added decibels the safe listening time is cut in half. That means 82 decibels has a safe exposure time of 16 hours, and 79 has a safe time of 32hrs. As such, we can work out that a round figure of 80 dB has a safe daily exposure limit without risking premature NIHL.

In addition, if we wanted to find out what the accumulative exposure to a level of sound would be for a twenty four hour period, we can also roughly work it out.

For 80dB, an accumulative reading per minute from the sensor would total 288,000 at the end of a 24 hour period. For 85dB, it would be 331,200, for 90dB, 388,800.

With this information we can read the sensor data, interpret it and tell the LEDs how to respond in a manner that represents the immediate environment.

Achievement reached!

We set ourselves goals to reach, so at each stage we would have something we could hand in, before we moved on to add the next part in. And today, finally, we reached our first goal, to read the sound data, and visualize it in a way to give instant feedback to the wearer.

The problem is, our sound sensor is still being a bit dodgy, so I’ve had to rig the code a little bit for testing purposes, but I still have the true science bit in (commented out) in case anybody asks!

Here’s the code:

int sensorPin = A0;
int ledPin[] = {3,4,5};

//int warningLevels[] = {200, 230, 270};
int warningLevels[] = {20, 50, 100};

int sensorValue = 0;

int accumSound = 0;
int readCount = 0;
int aveSound = 0;

int ledLit = 0;

void setup()
{
  Serial.begin(9600);
  //set up LEDs
  for (int i = 0; i<(sizeof(ledPin)/2); i++){
   pinMode(ledPin[i], OUTPUT); 
  }
}

void loop()
{
  //turn the lights off
  for (int i = 0; i<(sizeof(ledPin)/2); i++){
   digitalWrite(ledPin[i], LOW); 
  }
  ledLit = 0;

  //read sensor
  sensorValue = analogRead(sensorPin);
  //remove errors
  while(sensorValue == 0 || sensorValue > 350){
   Serial.println("reread...");
   sensorValue = analogRead(sensorPin); 
  }
  //trace
  Serial.print("sensorValue: ");
  Serial.println(sensorValue);

  //add to accumulative sound
  accumSound += sensorValue;
  //trace
  Serial.print("Accumulative Sound: ");
  Serial.println(accumSound);

  //add to readCount
  readCount++;

  //work out average sound per minute
  aveSound = accumSound/readCount;
  //trace
  Serial.print("Average Sound per min: ");
  Serial.println(aveSound);

  //check against our set levels
  for (int i=0; i<(sizeof(warningLevels)/2); i++){
   if (aveSound > warningLevels[i]){
    ledLit = i+1;
    Serial.print("Warning level breached: ");
    Serial.println(i);
   } 
  }

  ///light correct amount of LEDs
  for (int i=0; i<ledLit; i++){
   digitalWrite(ledPin[i], HIGH); 
  }

  Serial.println("------------------------------------------");

  //wait for 1 minute
  delay(30000);
}

I’ve done my best to comment it well, but incase you can’t work out what it does, basically it reads the sound every 30 secs, adds this to a accumulative score, works out the average sound you’ve been subjected to per minute from that, and lights the LEDs if you’ve had over the recommended limit per minute.

 

I’ll let Karla explain the science behind the recommended limits she came up with, but they’re basically 80,85 and 90 decibels, which we think should correspond to 200, 230, 270 from our sensor. However, these values are never hit, even if the sound sensor on Karla’s phone says we’re above those decibels, so I’ve added random levels in for testing.

 

I’ve currently been running it, with the wifly board in but not working, on battery for seven minutes and it’s still going strong.

Next up, we have a break for a dissertation seminar, then we’ll get the wifly working. We have a vague idea of sending the data to twitter, and pulling the feed from it to visualize it, but we’ll see how we go. At least now we have something to show if all else fails.

A mess of wires

This is the current state of our set up – a mixture of sensor, wifly, wires (more organised than they look) and LEDs.

Our project has developed through the limitations and freedoms of our discoveries, between finding ways and incompatibilities with different parts of kit and thinking new ways to do things to improve upon the original concept. We’d like to give the final result a more immediate response to the data it is discovering, and we’ve removed the idea of using GPS due to the want to completely avoid any privacy concerns. Thus, we’ve rearranged our ideas for output and as such expect that the hat-scarf-bear will have three “claws” on one paw comprised of three LEDs, two green – for good and manageable levels of sound – and one red, for determining and warning of dangerous levels of sound or noise in the immediate area.
We’re also intrigued by the idea of linking the bear up to a twitter feed, so that we can not only share/broadcast this information but encourage other people to find ways of using the data, as well as ourselves. The purpose of the decibear is to raise awareness after all, and while the awareness in concept may be unique to the individual wearer, online it can become the awareness of many more, even if in a secondary state.

Suddenly Sound

I figured out what was causing us so much trouble with the sound sensor – we’d been pinning it up wrongly the whole time! Where in the diagram that we had been following it showed us to connect it in a certain way, I found that exchanging the ground and sensor made it work, whereas previously we were connecting to the sensor but it wasn’t responding to loud sounds.

Similarly, we later discovered what the problem with the Wifly shield was as well – that it wasn’t compatible with my Mega 2560 Arduino board. Solving the issue turned out to be rather simple, a case of wiring four pins of the shield to a different part of the board.

20130219_125734