Introduction: FuseBerry: a Musical Fan Using a RaspBerry Pi
The FuseBerry is a musical fan based on a RaspBerry Pi. A distance sensor will be used in order to determine the pitch and the volume of the note.
Basically, the pitch will be determined by the frequency of the fan oscillations while the volume will be handled by the average distance measured by the sensor.
The fact that we can't really control the exact frequency of the fan oscillations will create interesting and unexpected sequences.
Moreover, we wanted it to come with an integrated website, that explains how it works!
The team is actually composed of 3 engineering students in electronics and computer science for embedded systems in Polytech Paris-UPMC and this was our class projet.
Step 1: Materials
For this project, you'll need the following components:
- 1 x RaspBerry Pi (2 or more) Model B;
- 1 x 5V Voltage Regulator
- 1 x IR distance sensor
- 1 x 5V Precision Voltage Reference
- 3 x operational amplifiers. We used 2 LM358 as we don't need negative voltage in this project
- 1 x MCP3008 Analog to Digital Converter
- 1 x JFET Transistor (N5332)
- 1 x Diode
- 1 x 150 nF
- 1 x 33 nF
- 1 x 1,5 uF
- 2 x 100 Ω
- 1 x 220 kΩ
- 1 x 470 kΩ
- 2 x 1 kΩ
- 1 x 820 kΩ
- 1 x 470 Ω
- 1 x 560 Ω
- 1 x 120 kΩ
Step 2: Analog Part
The attached schematic describes how the output voltage of the distance sensor will be handled by the electronics:
First of all, the output signal is splitted into 2 channels. The first one will be used for the velocity while the second one will determine the pitch.
1 - Velocity:
As we want the average distance to determine the volume, we only want to keep the continuous current component. Thus, the note will be loud when the fan is excited near the sensor. On the contrary, using the fan far from it will reduce the loudness of the current note. However, it is imporant to keep in mind that the sensor can only be used between 10 and 80 cm and will not be effective out of these bounds.
In order to do this, we first apply a low-pass filter to this channel, with the lowest cutoff frequency possible. We chose to make a passive filter with R = 820kΩ and C = 1.5uF. The cutoff frequency is thus close enough to 0Hz. and the oscillations are going to be ignored. Then, we simply apply a non-inverting amplifier in order to rise the gain and get an output that could easily be used by the RaspBerry Pi. We chose the same R values (100Ω) in order to rise the gain by multiplying it by 2.
2 - Pitch:
The pitch will be determined by the frequency of the fan oscillations. Quick oscillations will correspond to a high note while slow oscillations will correspond to low notes.
As we want to determine the frequency thanks to the Fourrier transform, we want to produce a sine that is the purrest possible. In order to do that, we first apply an automatic gain control, based on an envelop detector and a JFET transistor. By doing this, we want the gain to be the as constant as possible despite the average distance in order to get clear oscillations.
Then, we apply a low-pass filter in order to delete the noise and unintended frequencies. As we only want to keep the frequencies that are under 10Hz, we chose R = 120kΩ and C = 150nF.
We finally apply another non-inverting amplifier in order to rise the gain and get another output signal that can be easily treated by the numeric part.
However, it is really important to keep in mind that the frequency of these oscillations (up to 10Hz) won't be the frequency of the note, as it is difficult (not to say impossible) to generate audible frequencies (from 20 to 20kHz) with the hands.
As the RaspBerry can't provide a high current, this circuit is power supplied by 6x1.2 batteries and a 5V Voltage Regulator.
Step 3: Analog to Digital Conversion
Unlike the Arduino, the RaspBerry Pi does not have any Analog port. It is imortant to use an A/C Converter, such as the MCP3008. It comes with a SPI interface that easily allows it to communicate with the RaspBerry Pi.
Moreover, it provides 8 input pins. We can use it to convert the 2 signals that we want the RaspBerry Pi to use.
It is important to plug it as shown bellow in order to make it work with the provided code.
Note that the converter needs a really stable voltage reference, that's why we decided to use a 5V Voltage Reference instead of pluging it directly to the 5V Voltage Regulator used previously.
Step 4: Programming the RaspBerry Pi (1/2)
The current section will not explain in detail every line of code but it will explain how it's built and how it basically works. The provided C++ files and Makefile compile and work without error nor warning but you're free to explore it further if you want to truly understand how it works.
1 - Installing the libraries :
Before trying to compile the provided code, note that it requires a few libraries that you can easily find and install:
- GNU Scientif Library (GSL), that will be used to execute the Fourier transform. You can install it by entering the following line command : sudo apt-get install libgsl0ldbl.
- ALSA Sound Library, that will be used in order to generates output sound directly into the speakers. You can install it by typing : sudo apt-get install libasound2.
- Pthread Library, that is much faster that using the fork() function. It generally is a native library but you can easily find in on the internet.
- WiringPi Library that is essential to make the RaspBerry works with GPIOs and electronics.
- All other libraries come with the build-essential package (time.h, unistd.h, iostream...), that you can install with this command : sudo apt-get install build-essential.
2 - Threads Diagram :
As we want the output frequency to be directly connected to the input one, we decided to organize the code in several threads that will work concurrently. The attached diagram represents the different interactions between all of these.
Step 5: Programming the RaspBerry Pi (2/2)
Before going any further, you have to know how threads work. To keep it simple, we assume that threads are pieces of code that are executed in a concurrent way. Thus, it may happen that several treads want to access the same data at the same time. These data, that are called "Critical Section" basically need to be protected by mutex. Typically, when one thread is going to use one of these data, other threads won't be able to access them and will wait until it is freed.
All the threads are executed in an infinite loop.
1 - MPC Threads
First of all, there are 2 MPC threads, that correspond to the data the RaspBerry is receiving from the MCP. The first one corresponds to the frequency (that will be used for the pitch) while the second one corresponds to the velocity.
The MCP Note thread is constantly filling an integer circular array (of size 1024) while the value of the velocity is constantly read by the MCP Volume thread and written in a simple integer variable.
As we want the FFT to be constantly executed while the circular buffer is filled, the MCP Note thread is also copying the 128 last values into another integer buffer that will be treated by the FFT.
Note: By using a circular array, it becomes possible to read the 128 last data at any time and not get unintended delay by waiting for the array to be filled
2 - FFT
As it is mentionned previously, the MCP Note thread is constantly filling an integer buffer of size 128. As it is protected by a mutex, this buffer is actually filled with the 128 last values of the circular array once the FFT is done and doesn't need to access it anymore.
Thus, the circular array can be constanty filled while the FFT thread is executed.
Finally, this thread is returning an integer that corresponds to the average frequency of the 128 data read.
3 - Choose Note
Once the frequency returned by the FFT is available, an algorithm is then executed, in order to determine the output frequency corresponding.
For now, this algorithm is only able to return a frequency that corresponds to a note from C Major (C, D, E, F, G, A, B) but we aim to implements push buttons and leds in order to allow the user to choose the notes by himself.
To keep it simple, this algoirthm uses a float array and a boolean array. The first one is filled with the frequencies of all the notes of an octave while the second one corresponds to the selected notes. By dividing the input range (0 - 10Hz) by the number of selected notes and then dividing the input frequency by the previous result, it becomes possible to get the index of the output note (that will be directly linked to the frequency float array).
4 - Audio Ouput
Finally, once the output frequency and the velocity are available, the Audio Output thread is generating a simple sine (by using the math library) that will directly be read by the output speakers, thanks to the ALSA library.