Arduino

A year of pIoT, lessons learnt

About a year ago I posted about an Internet of Things platform I was developing for my home: pIoT.

The platform includes a simple hardware design based on the ATMega328 micro-controller (the same as Arduino UNO), an Arduino compatible firmware, and a server, actually two servers, one made in Java and another made in nodeJS.

In April 2015 the development of the platform was more or less completed, and I started deploying nodes around the house where I am living. Plus, I dedicated a small computer to the server and a node as a gateway between the server and the rest of the network.

So the situation, at the moment, is like this:

Server

it’s composed of a Raspberry PI and a node attached to it with a USB to TTL module.

IMG_20150905_171737.jpg

The software running in the server is the version based on nodeJS (see some screenshots below). As CSS framework I have used Bootstrap, so that the web page is also easily visible on mobile phones.
The server has several functionalities:

– it gives a summary of the status of the sensors and some measurements (dashboard)
– it allows connecting to the serial port and give basic input/output
– it parses the messages coming from the pIoT node (which are in JSON)
– it sends messages to the pIoT network, for example to control some actuator
– it stores all received data into a no-SQL database (nedb) and allows visualising data and plotting simple graphs
– it allows setting up rules so that when some data arrives, an action can be performed

This slideshow requires JavaScript.

The device is located in the conservatory of the house, this choice was due to the fact that it was half way between the router (giving Internet access) and most of the nodes.
I have also setup a dynamic DNS and a static port routing so that the server can be accessible from outside of the local network (no, I won’t give you the address).

Nodes

there are three nodes at the moment in my house (not considering the one connected to the server).
One node measures light intensity, temperature and soil moisture. It is located in the conservatory and also measures the moisture of the soil of a plant. The intention is to monitor the status of the plant and warn when the level of water is too low. The node is operated by two AA batteries and sends data each hour. In a previous post, I described how to build the moisture sensor.

IMG_20151210_093915

A second node is located outdoor. It measures light intensity, temperature, humidity, soil moisture and the presence of rain. Its main purpose is to give information about the weather. This node is operated by 3 rechargeable AA batteries (it needs a low-power voltage regulator to not burn the radio module) and a 6V solar panel. It also sends data each hour.

IMG_20151210_093844

A third node is located indoor, in my bedroom. It measures light, temperature and humidity and has a powerful RGB LED that can be activated remotely (in that sense it’s both a sensor and an actuator). The intention is to monitor the temperature in home and to have a sort of visual output of the system. This node is operated by a USB charger, so it includes a voltage regulator to bring the voltage down to 3.3V. The bedroom is located opposite to the conservatory in the house plant, so data transmission is quite difficult as there are some walls to be traversed. Data are sent each hour, but the node is continuously listening for incoming commands, that’s why the choice of powering it from the line, otherwise batteries would have been consumed very quickly.

IMG_20150905_162206

Collected data

So far I have received 27359 messages. Most of the messages (12801) are of type “hello” which is sent by all nodes and describes the internal status of the node. These messages include information like the number of packets lost, the operating voltage, the internal temperature as measured in the microcontroller.
Another big chunk (11360 message) is represented by “garden” messages which are sent by the outdoor node and the one in the conservatory. These messages include temperature, light, humidity, rain presence and soil moisture.
The other two categories of messages are “room” (3161 message), that contain information about the light, temperature and humidity of the bedoorm and “color” (only 37) which descirbe the status of the RGB LED.

Consider that the system was not always 100%, 24h/24 ON. It had some down times because I was updating something, or because the power went off or other reasons. But I can probably say that the system was ON at least 80% of the time within this year.

In total, the database occupies about 4 MB, which is prefeclty bearable by the Raspberry. Consider that nedb loads all the data into memory, so, if the DB grows a lot, probably I’ll have to archive some old data.

So now that we know what is the deployment and what data is there more or less, here’s the lessons learned.

Lessons learned:

Crappy batteries are… crap

I have used a wide range of batteries during this year. From expensive Duracell, to very cheap batteries bought in Poundland. Well, the difference is evident.

In the following graph you can see how fast a “good” battery is depleted on a node sending a message each hour.

batteries_good

That’s about 2 months. Now see what happens with cheap batteries:

batteries_bad

That’s only about 2 weeks!

In theory, at the rate I am sending data now, if you switch all modules off properly, batteries should last several months if not years. I am not sure why I am consuming power faster than foreseen, I have tried different approaches to improve it, but the situation doesn’t change. Changing batteries every 2 months is not too bad, but it’s not ideal either.

Solar works!

So, here a possible solution to power consumption: adding a solar panel.

And it works!

During winter I had to charge the batteries myself manually about 3 times. Since days have started to last longer (about March) I have never had to recharge the batteries again!

solar

In the graph you can see that the voltage is practically constant at 3.4V except one value, probably an artefact.

Packet loss is inevitable

pIoT configures the NRF24 module to retry transmitting a packet up to 7 times in case of failure. This gives a good amount of assurance that the packet is sent, if the connection is good enough. Even with this setting, packet loss happens.

I have computed the average packet loss for a the three nodes installed at home: for the node located in the conservatory, I get 18% of packets wasted, for the one outdoor: 24% and for the one indoor, almost 51%. That’s quite a big percentage, but it’s also expected. The nRF24 module was not designed for this range. Even though it says that it can reach 100 m, in reality it was thought for very short range communications, like for wireless keyboards or mouse. Still, it’s quite impressive that we can get useful data in an environment such as a house made of bricks.

… and sometimes it works unexpectedly well

It is not surprising that the node located in a room opposite to where the receiver is has such a high packet loss. Actually it is quite surprising that it receives data at all.

I have also observed that, when packets are sent by the server though, they are quite likely to be received by the node even though the packet loss on the other direction is pretty high. I don’t know exactly why, but it’s pretty reliable. And that’s also a very good news as, in fact, that node is used to warn the user when some action has to be taken (like pouring water to the plants,).

August is nicer than December

That’s a pretty obvious one, at least here in UK. Let’s see it from the perspective of natural light. The following two pictures show the light as measured by the outdoor node in a day of August 2015 and on in December 2016. You can see clearly that in August light starts at 4:00 and ends around 20:00, while in December it starts at 8:00 and ends at 16:00. Eight hours difference!

This slideshow requires JavaScript.

If we look at the outdoor temperature on two random days of August and December 2015:

This slideshow requires JavaScript.

Temperature in December spans from few degrees over 0 to 10 degrees (Celsius). In August we get temperatures between 10 and 20. It’s interesting to see that the range of variation in a day: in both months it’s about 10 degrees.

…but my room’s temperature is stable

the two charts below show the temperature in my room as measured by the indoor node. One chart is related to a day in August, the other to a day in Feburary.

As you can see, although there’s an obvious difference between the two days, the temperature, is quite stable throughout the day.

This slideshow requires JavaScript.

Micro-controller internal temperature needs calibration

I have used this trick to measure the internal temperature of the ATMega328. I have calibrated the raw values as received by the ADC with a thermometer I had at home and using an air dryer to raise the temperature. There was a very clear correlation between the raw values and the actual temperature and the formula I gathered was:  temperature = (ADCW * 0.9873) – 330.12. This calibration was done on one single MCU.

When using the same formula on other nodes, though, it stopped working. As the charts below show, there is an evident correlation between the temperature as measured internally and as measured with a more precise DHT, but the internal measurement is not correct. This means that, basically, each single microcontroller needs a different calibration.

This slideshow requires JavaScript.

s*#t happens!

Yes, and very often too!

Here’s an example of actual 💩:

shit

Why do these things happen?

I have no idea, but I can only speculate that, although the NRF24L01 has its internal checksum, some data corruption happens anyway. pIoT libraries do not add an extra checksum, so, if you need absolutely clean data, you’d better add it.

Electronics is incredibly resilient

Well, mostly.

Look at this node:

it has been in the wild for 16 months: rain or sun, winter or summer, with high humidity, insects of all sorts trying to build their home inside, and it was all covered by just a plastic box (actually of cotton buds). It’s a bit rusty inside, but still, it was able to survive and send data without (almost) any human intervention.

Soil moisture measurement is not sustainable

The outdoor node measures moisture thanks to two metal nails.That’s not unprecedented, but it’s not very reliable either. The nails tend to get rusty and to corrode over time (see picture).

IMG_20160828_191915

Nonetheless, as a rough estimation, it’s still good enough. The following charts show soil moisture and rain over the same period of time. There is some sort of correlation between the two, although not very strong.

This slideshow requires JavaScript.

 

Conclusion

My personal conclusion is that pIoT, as it is now, is a very interesting prototype, but it can’t compete with commercial, ready-made solutions. I wouldn’t rely on my pIoT installation to run critical things like theft alarm, or fire extinguishers, but it’s more than enough for things like gardening, or just for learning some electronics!

There are surely other interesting, and maybe less-obvious, findings that can be derived from the data collected over more than one year. For example, from the indoor node I may get some behavioural information (e.g. sleep patterns). So I may update this post with some other findings if they occur to me later. Meanwhile, if anybody wants to have a peek at my data for doing some research, I’ll be happy to give them !

pIoT a pico/personal Internet of Things DIY platform

This post is a follow up and an evolution of this previous one. I am pretty proud to present here a work that has been going on for more than a year. It all started with some friends at MakeSpaceMadrid. We wanted to create a super-cheap, Arduino-compatible with embedded wireless communication, electronic board. We decided to adopt the very well-known Arduino UNO ATMega 328p as microcontroller and the nRF24L01 wireless chipset as communication module, both sold for about 1€ on the Chinese market. We called our project Sensorino. We did a lot of things, but the project took longer than expected. Its code is still on github and everybody is welcome to contribute. While Sensorino was slowly being developed, I forked it on a personal, simpler project, and called it pIoT.

So what´s pIoT?

It’s a collection of three things: a hardware design for custom boards with a microcontroller and the wireless communication chip, the firmware that runs on the microcontroller and a server that collects data, shows it and executes rules. The project is open source and available on github for anyone to download or contribute.

pIoT board

A pIoT board

At the moment most of the functionalities are there: the board design is extremely simple, it’s just the ATMega328p connected to an nRF24L01+ module, the firmware contains a library for exchanging messages over the nRF24 module, a library for managing energy consumption (that is, putting the microcontroller into sleep modes) and a library for exchanging JSON messages with a host computer, the server software is programmed in java and takes care of parsing packets, visualising data on web using GWT and implementing rules using the mvel expression language. A new version of the server for nodejs is also on its way.

server

A screenshot of the server interface

The topology of the network is simple, there is one “base” node connected to a host computer through a serial port, the computer running the server code, and a set of “peripheral” nodes, which can be both sensors or actuators, that send/receive data to the base. More complex topologies are possible, but routing is not supported at the moment (for this, I suggest the very interesting RadioHead project). I am writing a tutorial for helping set up the whole thing.

pIoT topology

pIoT topology

I have created a testbed at home, with an old laptop working as server (a Raspberry Pi would also do) and two nodes, one that senses data from a plant (as already published a in previous post) and one that acts as a remote controlled colour LED. It works, and, as far as now, battery consumption is quite good. I have had the plant sensor running on two AA batteries for a couple of months.

pIoT server

The pIoT server

Garden pIoT node

A pIoT node in the garden

 

There are still things missing of course, but a complete proof of concept is already there and promising. If you are interested in the project and willing to collaborate, I will be very pleased to help!

A simple Arduino garden sensor

This is not the first time Arduino is proposed for gardening, you can see nice examples here and here, or here, and even here. Anyaway, I would like to tell you how I made it even though it’s not that original.

My sensor has three elements: a moisture sensor for the soil, a light sensor and rain sensor.
Let’s see the three parts separately.

Light sensor:

it’s a very standard LDR (photoresistor) example, like this one. You connect an LDR between 5V and an analog pin and the pin to a 47KΩ resistor that goes to ground.

 

Moisture sensor:

I have used two nails as electrodes, as suggested in many places, like here. You need two long nails and a sponge. You solder the nails to two wires. If you can’t solder the wires, just wind them around the nails and solder just the wire. The you cut the sponge to obtain a rectangle of 5cm long and you put the nails inside, this way the wires won’t go away easily.

Then you connect one of the two wires to the 5V pin, the other to an analog pin and you connect the same pin to ground through a 10KΩ resistor.

The principle is simple, the two nails are put into the soil and act as electrodes. If the soil is completely dry, there will be no current between the electrodes and the value measured at the analog pin will be zero. With a lot of water there will be a relevant current between the nails and the measured value will be higher.

I have done some experiments and my values are like this:

dry soil: 0
some little water: 200-400
some fair water: 500-700
quite a lot of water: 700-750
soaking wet: 800-…

 

Rain sensor:

I was inspired by these kind of sensors they sell on the Internet. To emulate it, I used a proto perf PCB board the kind with holes connected in lines. I used a thin wire, peeled a piece of it, double the length of the board and “sewed” it around the lines in order to connect lines two by two. Then with another wire you do the same but with the lines that are not connected yet. This way half of the lines (the even) belong to one wire and the other half (the odd) to the other wire. When a drop of water falls between two lines, it generates a little current that can be detected by the Arduino. To wire it to Arduino, you connect one wire to 5V, the other to an analog pin and the same pin to ground with a 10kΩ resistor.

By measuring the values at the analog pin with different amounts of water I get these:

dry: 0
some drop: 300-400
fair a mount of water: 500-600
soaking wet: 800-…

 

At the end, when you put all together you have something like this:

Regarding the sketch to be used on the Arduino it’s up to you. At the moment I am just measuring the values of the analog pins and doing some experiments (the code is not even worth publishing).

 

A minimal Arduino-compatible board with wireless connectivity

The subject of this post is a project I am involved in Makespace Madrid with some friends.

Our idea is to create a minimal Arduino-like board with wireless connection in. The project is being documented on the Makespace wiki (in Spanish). Basically we took an Atmega328p (the heart of Arduino Uno) with no strings attached and connected to a nRF24L01+, a super cheap, super low-cost 2.4GHz digital transceiver. The Atmega alone can be used as an Arduino, but at 8MHz. This post explains how to do it in detail.

This idea is not new. Just google “Arduino nrf24l01” and you’ll find examples like this, or this.

The connection between the Atmega and the RF board follows the instructions given in this post:

  • PD2 -> IRQ
  • PB0 -> CS
  • PB5 -> SCK
  • PB4 -> MISO
  • PB3 -> MOSI
  • PB1 -> CE
  • GND -> GND
  • VCC -> VCC

A quite raw prototype I have made is visible in the picture:
Image

I have also added a RGB LED to three pins of the Atmega with PWM.

As software, you will need a library that implements the communication with the RF chip (it works with SPI). I have tried the Maniacbug’s library RF24, but, a part from the basic examples that come with the library, I was not able to make my own wireless controller. I even tried some forks of the same library as suggested by Matthias Hertel in his post but wasn’t successful. I then tried the library provided by Mike McCauley here, and it worked very well at the first try!

As a demo I have created a simple sketch that can work in two ways: as a “client” that receives simple messages composed of 3 bytes, one per each color (RGB), and switches the LED on accordingly, and a “remote control” that reads these values from the serial connection or from three potentiometers and sends them. The code is available in my repository here.

Below you can see a video of the demo, the “client” is my prototype board with the LED and the “remote control” is a normal Arduino connected to a nRF24L01 and 2 potentiometers (I didn’t have a third one available !!).

LightBox: a VJ-oriented LEDs controller

Hi,

this is probably the first complete and usable device I have been able to make with an Arduino, so I am very proud of it!

An undecorated version of the LightBox

LightBox, a VJ friendly RGB LEDs controller

Recently we have seen the explosion of bright, colored RGB LEDs everywhere. Their cost has been going down tremendously, so that now you can easily buy meters of LED chained in strips for few euros.
These strips usually come with some sort of controller which is OK for your home, or a Christmas tree, but may miss some functionalities in other contexts.

The objective:
I want to use an LED strip as a complement to my VJing performances, for example, putting a strip on the front of the stage and making it flash according to the music. More concretely I want to have separate control for luminosity and for color (as in a performance you can be more interested in the amount of light than the color itself). Then I want to have some oscillators for both light and color and be able to control their speed, and I want to have luminosity and/or sound to be controlled by the music, or, more specifically, by the bass (to have lights in sync with the rythm).

The materials:
It’s pretty simple to control an RGB LED strip with an Arduino and three TIP120 transistors, so I decided to build my own custom controller.
As the RGB color space does not separate color and luminosity I have adopted the HSV color space which has different dimensions for value (luminosity), hue and saturation .
The controller interface should have then:

  • A pot for increasing/decreasing luminosity
  • A selector for activating oscillation or music control
  • A pot for controlling the oscillation speed
  • A controller for the saturation value (from white to fully saturated)
  • A pot for selecting the hue
  • A selector for the color oscillation
  • A pot for speeding up/down the oscillation

You can see how the final interface in the following picture:

The LightBox interface

The LightBox interface

For the electronics I have used an Arduino Diecimila as a controller, three TIP120 for controlling the 12V current needed to lighten the LED strip, a couple of commuters, and a bunch of linear, 10K potentiometers, with both horizontal and rotation controlled. Then, of course, a 3 meters LED strip, its particular 4 pins connector and a sufficiently powerful 12V source. For catching the sound I have used a pre-amplified mic kit form Sparkfun.

I have soldered all the components to a big protoboard, and soldered some pins to the back of the board so that you can plug it to Arduino as a shield (useful for replacing the board if needed!).

This slideshow requires JavaScript.

Everything is then put into a colored box, potentiometers with their caps, and some printed decorations have been glued on the box. I made the decorations with Inkscape. For making the HUE circle I have used this trick.

The code of the controller is pretty straightforward: it just needs reading some digital pins for understanding in which position the commuters are, then read the values of the potentiometers for getting the amount of saturation, hue and value, and control the oscillation.
As for the oscillation I have created three kinds: a triangular oscillation, which is nice and smooth, a square oscillation, for strobo-like effects, and a random oscillator.
There are two tricky parts in the code. One is the sound control, especially if you want to make the device reactive only to low frequencies. For this part please have a look at my previous post. The other tricky piece is the HSV to RGB conversion. Fortunately there are a lot of examples on the internet, and one specially thought for integers (much faster than float computation), though I had to slightly adapt it for Arduino has 16 bits integers and was making some errors in the calculations. You can download and use my code for free from my repository.

The results:

You can see a couple of pictures here:

And a video:

Bass detection with Arduino

This post is a continuation of my previous post about sound analysis in Arduino.

In this post I will explain how I concretely managed to synchronize a light to the low frequencies of music (that is the bass).

As seen in my previous post, there are several alternatives for doing this job, so I will focus on a particular selection of tools:

The circuit:
The easy one: I use the Sparkfun’s electret kit.
The algorithm:
I will try to create a FIR filter for selecting only the low frequencies of the signal, and I will not tweak the analog-to-digital sampling frequency.

As the circuit is trivial, let’s see the details about the algorithm. For designing the filter I have used a wonderful free online tool, TFilter, from Iowegian.

The tool allows specifying the sampling frequency and the frequency response of the filter.
In my case I chose to allow passing frequencies for 0 to 200Hz and to block frequencies from 300Hz on. You can see the graph of the frequency response of my filter below:

Low pass digital filter frequency response

Low pass digital filter frequency response

As for the sampling frequency it’s tricky. It, in fact, depends on the code which then depends on the filter that you have. Generating the right filter is therefore an iterative process: you generate a first version of the filter with a certain sampling frequency (say 5000Hz), you import the code from the online tool (the code is automatically generated for you in the “source code” tab) and stick into your sketch, then you run a sketch that measures the actual sampling frequency, for instance by filtering a thousand samples and measuring the time needed for that. An example of such code is the following:

#include "LowPassFilter.c"

//The number of samples to buffer before analyzing them
int samplesN = 1000;
int micPin = 0;

LowPassFilter* filter;

void setup(){
  Serial.begin(9600);
  filter = new LowPassFilter();
  LowPassFilter_init(filter);
}

void loop(){
  long pow = 0;
  long filtpow = 0;
  int peak = 0;
  long start = millis();
  for(int k=0; k<samplesN; k++){
    int val = analogRead(micPin);
    LowPassFilter_put(filter, val);

    int filtered = LowPassFilter_get(filter);

    pow += ((long)val*(long)val)/samplesN;
    filtpow += ((long)filtered*(long)filtered)/samplesN;
    peak = max(peak, filtered);
  }
  long end = millis(); 
  float freq = ((float)samplesN * (float)1000) / ((float)end - (float)start);

  Serial.print(freq);
  Serial.print(" ");
  Serial.print(pow);
  Serial.print(" ");
  Serial.print(filtpow);
  Serial.print(" ");
  Serial.println(peak);
}

This code takes 1000 samples, filters them and computes the power of the signal, both the filtered and unfiltered ones and the sampling frequency. The power is simply the sum of the second power of the samples divided by the number of samples.
Note that I am using the integer implementation of the filter (in the source code tab of TFilter you can select floating points or integers in the “Number format” field) because integers arithmetic is much faster than floating points one.

Once you know what sampling frequency you go back to your TFilter tool and redesign the filter with the actual sampling frequency, but, given that the specifications are changed, it is very likely that the length of your filter will be different now, fact that will affect the computation required to run it and, therefore, the sampling frequency again!

So you need to do this work of: designing the filter + measuring actual sampling frequency + adjusting the filter, in some iterations (2 or 3 should be enough).

In my case the final sampling frequency is 2500Hz and the filter has 31 “taps” (the more complex is the filter the more taps you need, the more time you need to make it run at each sample).

So let’s check that it really filters the signal around 200-300Hz. I connected a pair of headphones to the microphone and measured the power of the signal while emitting some sine signals through them. The results is shown in the following table:

noise 50 Hz 100 Hz 200 Hz 300 Hz 500 Hz 800 Hz
total power 265760 307555 427998 458491 464047 466989 483063
filtered power 163604 198169 378124 275661 161191 162059 181106
peak 623 772 1087 950 548 537 613
filter/unfilter(db) -2.11 -1.91 -0.54 -2.21 -4.59 -4.60 -4.26

in terms of decibel it is not very impressive, but it does some filtering though. The problem here is that the circuit gets a lot of noise and a significant part of it goes into the low frequencies so, for instance, when you push a 800Hz sine the Arduino gets the 800Hz + the noise, therefore the total power is not so low.

Now let’s do something with this signal, for instance synchronizing a light on the bass of the music. For that we can use the measurement of the power or, even a simpler measurement, the peak.

To make it more responsive, instead of sampling 1000 samples, we can get 200 instead, and, in order to make it adaptive to the noise and general sound level we can play this trick: as the peak will move between a minimum and a maximum, we take the current peak and map the interval between the average and the maximum peak to a 0-1023 interval.

The final code appears something like this:

#include "LowPassFilter.c"

//The number of samples to buffer before analyzing them
int samplesN = 200;

int micPin = 0;

LowPassFilter* filter;

void setup(){
  Serial.begin(115200);
  filter = new LowPassFilter();
  LowPassFilter_init(filter);
}

int index = 0;
int maxpeak = 0 ;
int minPeak = 1023;

void loop(){
  int peak = 0;

  for(int k=0; k<samplesN; k++){
    int val = analogRead(micPin);
    LowPassFilter_put(filter, val);

    int filtered = LowPassFilter_get(filter);
    peak = max(peak, filtered);
  }  
  maxpeak = max(maxpeak, peak);
  minPeak = min(minPeak, peak);

  index++;
  if(index == 1000){
    maxpeak = 0;
    minPeak = 1023;
  }
  int lvl = map(peak, minPeak, maxpeak, 0, 1023);
  Serial.println(lvl);
}

It’s a pretty simple code as you see. Remember to also add the .h and .c files generated by the TFilter tool and also check that the sampling frequency hasn’t changed (which probably has). Please note also that there is a counter (index) that, each 1000 iterations, resets the minimum and maximum detected values. This helps if the sound level changes and you want your code to adapt to it.
From this code you can also make a sort of beat detector, for instance by setting a threshold and counting the number of times the peak goes on top of the threshold in a certain time window, but it would require more elaboration for sure.

In this code I am not activating any light, I am just sending the data to the computer to see how it is working. As the numbers run really fast on the serial monitor, I have created a simple Processing script that acts as a sort of equalizer bar, the code is here:

import processing.serial.*;

Serial myPort;

float MIN_VAL = 0;
float MAX_VAL = 1023;

void setup () {
  size(300, 500);        
  println(Serial.list());
  // Open whatever port is the one you're using.
  myPort = new Serial(this, Serial.list()[0], 115200);

  // don't generate a serialEvent() unless you get a newline character:
  myPort.bufferUntil('\n');
  background(0);
}

void draw () {
  // everything happens in the serialEvent()
}

void serialEvent (Serial myPort) {
  String inString = myPort.readStringUntil('\n');
  if (inString != null) {
    // trim off any whitespace:
    inString = trim(inString);
    // convert to a float and map to the screen height:
    float inval = float(inString); 

    inval = map(inval, MIN_VAL, MAX_VAL, 0, height-20);
     background(0);
    rect(10,10, width-20, inval);
  }
}

I have tested with some disco music and I have o say that the effect is quite good, when the bass is pumping you really see the bar going up and down at the same tempo, though, I have to say, you can also see some delay, which does not matter as long as you want to make some light controller anyway. By reducing the number of acquired samples to something less than 200 (for instance 100) you get a more responsive system but also a more sensible one, which makes the bar moving really fast and sometimes you see the noise clearly getting into the animation.

Sound analysis in Arduino

In this post I’ll show how I have tried to capture sound on the Arduino and make some simple frequency analysis on it. The possible applications are several, like having a LED tone visualizer as the one shown here, but my specific purpose is to synchronize a light with some music, particularly on the low frequencies. While mounting the system I have explored different possibilities and I have written what I have discovered in this post.

The circuit

for the circuit you need a microphone and an amplifier to put the voltage range into 0-5V as required by the ADC of Arduino.

Now ideally what you want is something that should give values form 0 (no sound) to 1024 (maximum detectable sound) and should add no noise, but in reality what you can get is that the mean measured value at the ADC is around 500 (the sound is a wave by definition so you have to move its center value between 0 and 5V = 2.5v), the circuit will add some noise, and is not always easy to have the full range of values (that is from 0 to 5V or 0 to 1024 at the ADC).

I have done experiments with three alternatives:

Alternative 1: opamp amplifier

As I wanted a cheap and dirty approach I decided to use common opamps. The drawback is that these often are not used for audio applications, and the quality of sound and (especially) the level of noise can be horrible !

The schematics I have used is exactly the same as on this page a part the fact that I have used a single UA741 amplifier instead of the LM358. You can find other similar circuits on the web like this one and this one. The microphone I am using is a standard electret microphone like this one.

Sound amplifier with opamp

Sound amplifier with opamp (taken from here)

I have connected the output to my headphones and it works, you can actually hear the sound of the microphone amplified, but… you hear a lot of noise too. The reasons for this noise can be multiple: the electromagnetic interference flowing into my un-shielded, long wired prototype, the opamp that is not designed for audio applications and others I am not even aware of.

Now let’s plug the circuit to the ADC of the Arduino and let’s see what values I receive.

I have made a similar analysis as the one done by Dimitar in his post. Actually I have used his same sketch that computes minimum and maximum peaks plus the peak to peak difference for 10000 samples (about 1 second).

I have tested four values of R5 resistance:

R5 Almost silence Talk Strong sound
10K range: 4 AVG: 509 range: 23 AVG: 507 range: 208 AVG: 509
56K range: 17 AVG: 508 range: 35 AVG: 510 range: 525 AVG: 510
100K range: 30 AVG: 510 range: 68 AVG: 509 range: 533 AVG: 508
150K range: 41 AVG: 509 range: 109 AVG: 509 range: 537 AVG: 507

You can see that the differences between the range at high volume and the range at silence are 204, 508, 503, 496 which leads us to say that the 56K resistance is the one that optimizes the dynamic range (a very similar conclusion to the one given by Dimitar in his post).

You can also see that the, being the average value at around 510 the maximum and minimum sampled values can be around 240 and 780, which means that the circuit is not able to output the full 0-5 V range, even with a high gain. Actually the 150K adds very little to the range, meaning that we have already reached the saturation of the circuit (it was also possible to see it with headphones).

So let’s fix the resistance to 56K and let’s do some of the frequency response of the circuit. For this I have used the very nice free TrueRTA program. I connected the audio output (the headphones jack) to the input of the amplifier circuit and the output of the circuit to the audio input (the microphone jack) of the computer.

This is what happens if no signal is given as input to the amplifier (that is no sound emitted from the computer):

You can see that there is a lot of noise at almost all frequencies and that the noise is even saturated (probably because the signal is too big for the microphone input of the computer).

Now let’s produce some white noise at half of my computer volume and analyze the amplified signal in my audio input:

Response to white noise of the opamp audio amplifier

Response to white noise of the opamp audio amplifier

you can clearly see that the circuit behaves as a high pass filter with attenuation at low frequencies.

Now let’s see the response at 100Hz, 1000Hz and 10000Hz:

You can clearly see the peak at the corresponding frequency in the three cases of a gain of about 10db from the noise level. You can also see some harmonics generated by the saturation  pretty clear. In fact, plotting a sine signal at 500Hz, at half of the computer volume you get:

Signal at 500Hz taken at the computer audio input

Signal at 500Hz taken at the computer audio input

which shows very clearly that the signal is saturated. Now this saturation can be introduced by  the amplification circuit itself, or it can also be introduced by audio input of the computer which is designed for microphones, that is, low currents.

Alternative 2: transitor amplifier

The Arduino Basic Connections manual has a page where it shows how to use a microphone with Arduino. I have mounted it but with a different transistor I had at home, the BC337 which seemed to me similar to the one recommended in the card, a 2N222. I have used my electret microphone, but the sound was hardly hearable in the headphones, only tapping the mic was recognizable. Maybe the circuit in the card is for stronger microphones? I don’t know.

Alternative 3: Sparkfun’s electret kit

I have also ordered the sparkfun electret microphone kit.

Sparkfun's breakout board for electret microphone

Sparkfun’s breakout board for electret microphone

I have connected the Vcc pin to the +5V of the Arduino and connected the GND and AUD pins to the audio input of my computer. Looking at signal generated by the microphone in almost silence we can see, on the computer:

you can see that there is already some noise, and that it is also saturated (though the amplification gain in the computer is set to its minimum).

Using some headphones and pushing with white noise in them:

White noise response of Sparkfun's kit

White noise response of Sparkfun’s kit

you  see a band-pass behavior, but we can never guess exactly what filters what as we have the headphones, the microphone, the amplification circuit and the computer’s input in a chain.

Now let’s analyse the range dynamics with Arduino:

Almost silence Talk Strong sound
range: 745 AVG: 512 range: 839 AVG: 508 range: 1023 AVG: 513

That proves that the circuit exploits the full range 0-5V completely, although it might amplify the signal quite strongly if compared to the opamp circuit whose range in almost silence was much smaller.

The audio analysis algorithm

Analog processing

You can always use analog filters to detect the signal’s spectrum in a set of possible bands. A common integrated circuit used in several projects is the MSEGQ7 which is able to give you the peak of the signal in 7 different bands around the following frequencies: 63Hz, 160Hz, 400Hz, 1kHz, 2.5kHz, 6.25kHz and 16kH. There is a good tutorial here, in this case you don’t need to do signal processing, nor you need to worry about sampling frequency and other stuff, you have the value of the peak right in your analog input 😉

Digital processing

In this case you have to address two separate problems here: sampling the signal and analyzing it in the frequency domain.

Sampling

A serious approach to audio analysis in Arduino would need increasing the sampling rate of the Arduino ADC. My Arduino Diecimila normally samples at about 10KHz (depending on the code you have in the middle, in theory it should be 9615).

It is also possible to sample at higher frequencies setting the ADC prescaler in a different way. With this trick you can reach 77KHz of sampling rate on ATMega168 without significant loss of quality. This page, this page and this other one explain the concept well.

Here are two examples of how to set the prescaler:

#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

//example 1: Set prescaler to 16 (= 77MHz) (1-0-0)
sbi(ADCSRA,ADPS2) ; //Sets ADPS2 to 1
cbi(ADCSRA,ADPS1) ; //Sets ADPS1 to 0
cbi(ADCSRA,ADPS0) ; //Sets ADPS0 to 0

//example2: Set prescaler to 64 (= 19KHz) (1-1-0)
sbi(ADCSRA, ADPS2);
sbi(ADCSRA, ADPS1);
cbi(ADCSRA, ADPS0);

According to this post the actual sampling frequencies are a little bit lower than the theoretic ones declared by ATMel in this order:

Prescaler        Actual maximum sampling frequency

16                 62.5 kHz

32                 33.2 kHz

64                 17.8 kHz

128                 8.9 kHz

I have also made my tests and with the standard settings of 128 I get frequencies (they vary a little bit) around 8920 – 8936 Hz and with a 64 prescaler I get 17825 – 17793 Hz which confirms the data of the post.

The choice of your sampling frequency depends on your application. In my case, as I want to analyze audio signals and I am especially interested into low frequencies, I will be happy to use the standard setting, 9/10KHz of sampling freq, which leads to 5KHz analyzable spectrum. In fact, 5000Hz is much below the audible spectrum (around 15KHz) but it is still quite a high pitch note (you can use this web page to get an idea of how it sounds).

There are interesting projects that make us of higher sampling frequencies, for example, here  or here.

A very cool and serious project is this one, which makes a complete digital signal processor out of an Arduino.

Analyzing the signal

The analysis of the signal depends on your application. You can go from very detailed frequency analysis to something very raw and simple.

Let’s see a couple of solutions:

FFT analysis

For sound analysis you can use a proper FFT or implement a FHT. A fast implementation of the FFT is available here also.

I have personally tried the FHT with the example sketch plus the PureData application it comes with and I have to say that I was amazed. I have been generating some tones with the online tone generator, passed them to the opamp circuit set to 50x gain, then fed to the Arduino in its analog pin 0. In the picture below you can see the FHT of a signal at 2000Hz.

FHT of a  computed in Arduino and shown in PureData

FHT of a 2kHZ tone, amplified by the opamp circuit, computed in Arduino and shown in PureData

You can clearly see the peak at 2000Hz and also some harmonics, probably a consequence of the saturation.

Digital filters

If you need to detect only few bands, another possibility for sound analysis are FIR or IIR filters, creating one filter for each band you want to detect. There is a very useful online tool for designing FIR filters here. If the bands you want to analyse are several, this approach wouldn’t save you so much computation with respect to the FFT as you will have to make several multiplications for all of your weights in the filter (which can be many, depending on how complex the filter is).

Other simpler approaches are possible, but based on the same principle, like in this other example. Unfortunately the code is not well commented and I couldn’t understand well how it works, as far as I have understood he sums the samples in groupa of 2, 20 and 100. The more samples you add the lower the frequency, but then some magic happens and I get lost.