Monday, 14 July 2014

Let's dance to the sound of piezos

Hi everyone, it's me, Sirio.

As I wrote in the last post, I found out that vibration motors do not have much "expressive power", not as much as I thought anyway. For this reason, I am switching to piezoelectric transducers, which offer a greater range of expression, are easy to control and wire up, and consume almost nothing.

At first, I wanted the piezos to produce a fixed pitch, and vary the volume of the sound as a function of the distance of the obstacles detected by the ultrasound sensors. Turns out, it is not that easy to do so with a piezoelectric transducer, as it would be with a buzzer.

Then I tried to vary the pitch of the produced sounds as a function of the distance of the obstacles, but I didn't like the result. I thought it would be quite annoying to listen to this continuous change of pitch while using the glasses for some time. The good thing is that it worked quite well as a theremin!

(Sorry about the noise, but piezo transducers produce very low sounds)

In the end, I decided to keep volume and pitch fixed, and vary the beeping rhythm, like in parking sensors:

The circuit here is quite simple - the mess you can see in the video is actually just because I was too lazy to tidy everything up. Each ultrasonic sensor is connected to Ground, to the 5V pin, and to a single digital pin (one for each sensor). In fact, with the NewPing library, you can use a single pin to ping the sensor, and to receive the reading.
The piezo transducers were just connected each to a digital pin and to ground. I think I will add some resistance to adjust the volume later on, and maybe a linear potentiometer to control the volume manually.

Now I can guide you through the code I've used here.
I'll explain the key functions and then show the complete code, I'm assuming you already know the basics for C coding.
This is the function which is called continuously as the Arduino is turned on. What it does is:
- Ping the US sensors.
- Average out the last READINGS readings, where READING is a number defined before.
- Shift the distance down of MIN_DISTANCE. This is used so that the piezos can already beep at the highest speed when an obstacle is presented at MIN_DISTANCE.
- Make the piezos beep.
The first and last actions in this list are actually carried out by two functions which are external to the loop. Let's have a look at the function which pings the sensors.

This function pings the sensors one at a time, retrieving the distance for each one. To do that, it makes sure that enough time has passed since the last ping (PING_INTERVAL).
Also, it both the US have been pinged, it updates the reading_n variable. That variable is used in the loop function to populate the reading arrays.

Now for the function that makes the piezos beep.
This function makes the piezo beep more or less frequently depending on the distance of the left and right obstacles.
When the right time interval has passed, the function starts a beep. A beep here is a square wave sent to a piezo for a certain PULSE_DURATION time.

The pitch of the beep sound is controlled by the R and L_BEEP_LOW_RATIO. Given that this function is called by the loop every 1 ms, if for example L_BEEP_LOW_RATIO = 2, then a series of HIGH - LOW - LOW is sent, where each signal lasts a millisecond.
The frequency of the resulting square wave is 1/3 of 1000 Hz (again, because the function is called every millisecond, 1000 times a second).

Finally the complete code, hopefully it should be easy enough now to read through.

OK, that's it for this post, hope you enjoyed it! For the next post, I will probably implement a third sensor to sense low-frontal objects (but I want to use only two piezo transducers).

I'll keep you posted!

No comments:

Post a Comment