Controlling the speed of a motor with sound input

Hello all. I am new to Arduino, and to the programming language, but I think it might offer a solution for my project.
I am looking to have sound input(could be analog or digital), specifically amplitude, control the speed of rotation of a small motor at very low RPM's, like between 4 and 12RPM's with no significant load on the motor.
I would simultaneously also like to have the amplitude of 3 specific frequency ranges(ie. Lows, Mids, and Highs), trigger 3 discrete relays when a predetermined amplitude threshold is reached in a given frequency range.

The project is a laser light show, where 3 different 30mw 3v colored lasers will shine through a piece of textured Plexiglas that will be mounted to a DC or PWM motor shaft. The concept is that the motor(plexiglass) will spin in time with the music, creating a really cool laser projection. Each of the three lasers will only illuminate when it's predetermined frequency range reaches a certain amplitude threshold.

I have found parts of the code I would need to do these things, but nothing that connects sound amplitude detection with variable motor speed, or frequency detection/analysis with the activation of relays. I am willing to try and learn the language, but some help here would be greatly appreciated.

I have purchased the following kit, plus an analog microphone and amplifier that outputs a 2-7V sound signal. Do I have all the necessary components to make this project work? Can anyone provide some examples of code that would allow for what I'm attempting? Should all this be feasible? Thanks all for taking the time to help.

I found a spectrum analyzer for the Arduino. Did not look at the code and you might have to dig for some hardware in previous articles but it might get you on thr right track for the frequency analysis.

Keep in mind that human perception of sound and what a microphone responds to are at best, very distantly related.

What you have in mind is actually quite difficult to accomplish, because humans pick out interesting or important characteristics of sound and ignore amazing amounts of noise and irrelevant signals. Microphones don't.

I strongly recommend to experiment with just a microphone/amplifier/Arduino and a test program. See if you can program the Arduino to discriminate different sounds, by printing to the serial monitor, before going any further with the project.

Should all this be feasible?

Yes... But as a 1st project, I'd suggest you start by making an LED get brighter/dimmer with the volume (you can use the pin-13 LED built-into the Arduino board). Then, try adding a motor driver so the speed gets faster when the LED gets brighter.

Take it one step at a time... When something is done, then you can try adding more features until it does everything you want.

When you're writing your code, take the same approach adding one or two lines of code at a time, test-compiling and test-running as you proceed. And as jremington recommended, make use of the serial monitor so you can see variables change, and you can send out messages about what the code is doing.

I am looking to have sound input(could be analog or digital)

I don't think you'll be using digital. :wink: Digital requires a specific format/protocol and the associated electronics, etc. USB? S/PDIF? HDMI?

I am looking to have sound input(could be analog or digital), specifically amplitude, control the speed of rotation of a small motor at very low RPM's, like between 4 and 12RPM's with no significant load on the motor....

...to a DC or PWM motor shaft.

You can control the speed of a DC motor with PWM. But to go that slow you'll need a geared-down motor (or a big load on a small motor). And, you'll need a motor-driver circuit because the Arduino cannot directly power a motor.

I would simultaneously also like to have the amplitude of 3 specific frequency ranges(ie. Lows, Mids, and Highs), trigger 3 discrete relays when a predetermined amplitude threshold is reached in a given frequency range.

The easiest way to handle that is with the [u]MSGEQ7 chip[/u]. It gives you 7 frequency bands, so you can either ignore some bands, or combine bands in software.

Or, you can do it entirely in software with FFT/FHT like the spectrum analyzer example.

The project is a laser light show, where 3 different 30mw 3v colored lasers...

...Each of the three lasers will only illuminate when it's predetermined frequency range reaches a certain amplitude threshold.

I'm not a LASER expert, but usually LASERs require a special power supply with additional special circuitry if they are to be "flashed" on & off. But, maybe low-power (30mW) laser diodes can be powered just like an LED... I don't know...

...but nothing that connects sound amplitude detection with variable motor speed, or frequency detection/analysis with the activation of relays.

That's something you'll probably have to figure-out yourself. Work-through and study some of the basic [u]examples[/u] and try to understand what the software is doing. Read-through the [u]language reference[/u]. If you are new to programming you won't understand everything in the language reference, but it will give you an idea of what you can do and it doesn't take that long to read-through.

The two most important concepts in programming are conditional execution ([u]if-statements[/u], etc.), and [u]loops[/u] (doing something over-and-over, usually until some condition is reached).

Once you understand those two concepts, you should have a basic idea of how to design and develop a program that does something useful.

...plus an analog microphone and amplifier that outputs a 2-7V sound signal.

Since the Arduino cannot handle the negative half of the AC audio waveform, you'll need to [u]bias the input[/u] (two resistors and a capacitor).

Thanks all for the fast and thoughtful replies. There's a lot of useful info in your responses, and yes, I will be doing much experimentation including many smaller tests.

To clarify, I have read through a number of example sketches, and have found parts of the scripting I would need, but haven't found anything that connects sensor input with variable but continuous motor speed. There's plenty of scripts that are based on variable resistance, but not on other forms of input data that I could find. Can someone provide an example of the type of coding that would be required for this? I'm willing to do the work, it would just be helpful to have a jumping off point.
It's also possible that although I have searched rather thoroughly, that I am looking in the wrong places for this type of information. Thanks guys!

There's plenty of scripts that are based on variable resistance, but not on other forms of input data that I could find.

Once you get past the hardware, there are only two kinds of input, digital (high or low, or 1 or zero) and analog (0-1023 when the ADC is read).

The chip doesn't know if that represents voltage, resistance, current, or loudness, etc. It's just a number you can use any way you want in your software. Your software knows what the number represents, because you wrote the software... (It's actually always reading a voltage, but that voltage could represent something else, and the 0-1023 analog readings don't have units of "Volts". It's based on a ratio relative to the analog reference.)

I won't attempt to give you the exact code because I don't have the exact same hardware as you, and I'm too lazy to try it out anyway...

But, the basic logic could look something like:
If analog input is greater than 100, turn the motor on.

A handy function might be the [u]map() function[/u]. The ADC input is 10-bits (0-1023) and the PWM output is 8-bits (0-255). With the map() function you can make the output proportional to the intput, so that the maximum 1023 input gives you the maximum 255 output, and half-input (512) gives you half-output (126).

You could create a variable for the input, another variable for the output, and you map the output-variable to the input. Then, you write-out the output-variable as PWM to control motor speed based on the input reading. (Higher input readings = higher motor speed, etc.)

Thanks DVDdoug. That is extremely helpful.

If I understand correctly, I would need to offset my incoming amplified AC 1-5v audio signal by +5V. I would then define the input and output pins, and would then utilize the map function to specify the input range as 6-10(the assumed rough voltage range after offsetting), and my output range as perhaps 0-250(or somewhere in between depending on desired speed range).

If I understand correctly, I would need to offset my incoming amplified AC 1-5v audio signal by +5V.

No. The two equal-value resistors will bias the input at half the applied voltage, or 2.5V.

If your audio swings from +1V to -1V (that's 2V peak-to peak), the bias will be added to that and the input to the Arduino will swing from 1.5V to 3.5V. Silence will read about 512 (half the 1023 ADC range). The FFT should treat the DC bias as zero-Hz, and you can ignore it, or you can subtract 512 from your readings.

If you are just looking for the "loudness", you can subtract and ignore the negative readings, or you can subtract and take the absolute value... Whatever you want to do. But, don't take an average and include the negative values... The average of an AC signal is always zero, and the average of your biased signal will be 512.

6-10(the assumed rough voltage range after offsetting),

Hopefully, your readings will be bigger than that. You'll have to experiment. With my made-up 2V peak-to-peak example, the positive peaks would give you readings of about 716 and negative peaks would read about 307. You'll get lots of readings in-between and they will always be centered around 512 (before any subtraction, etc.).

Dantor19:
To clarify, I have read through a number of example sketches, and have found parts of the scripting I would need, but haven't found anything that connects sensor input with variable but continuous motor speed. There's plenty of scripts that are based on variable resistance, but not on other forms of input data that I could find. Can someone provide an example of the type of coding that would be required for this? I'm willing to do the work, it would just be helpful to have a jumping off point.
It's also possible that although I have searched rather thoroughly, that I am looking in the wrong places for this type of information. Thanks guys!

The coding will be exactly the same. Read an analog voltage and based on the level turn a motor faster or slower (or make a LED brighter or dimmer). If you could turn a potentiometer (variable resistance) 100 times per second from min to max and back, you basically have a 100Hz signal.

Thanks sterretje. That's helpful. So, correct me if I'm wrong, but I'm thinking that a stepper motor will be a better choice, because I assume there will be a quicker response time. That being said, I am concerned about the smoothness of the operation at such low RPM's(2-10RPM's). I'm hoping to get away with the stepper in the kit, but I wont know until I get it, what the degree per step is.

Also, I'm a little unclear as to the best way to go about beat detection for controlling speed of a motor. I presently have an analog, full frequency, half wave rectified sound signal between .5v and 4.5V. Since, as a separate part of this project, I intend to use the amplitude of different parts of the frequency range to trigger relays(turn lasers on) I can't filter out the highs for cleaner detection of the beat. Will it be possible to simply use the amplitude of a full frequency sound signal to accurately detect the beat? If so, would that mean increasing the low value of a mapped analog input sensor range so as to only detect the spikes in amplitude?

I've taken the excerpt below from the "stepper_speedControl" example, and modified the values. I believe these new values indicate that the sensor reading range should be 2v-5v and that the stepper motor speed range should be 10/255(3.9%) - 100/255(39%). This should mean that we start detecting/reading voltage values after 2v and that the upper end of the readable range should be 5v. Also, it should mean that the stepper is always running at a minimum speed of 3.9% but when voltage over 2v is detected on the sensor, then speed increases proportional to the voltage increase, up to 39% of its full speed. Is this all a correct interpretation?

 int motorSpeed = map(sensorReading, 409, 1023, 10, 100);

No idea about steppers; don't know if they are the better approach and I have not played with them yet.

I think you have to define what 'the beat' is. I associate it with low frequency (like base drum) and the repetition rate of it; in my view it's not about the loudness (levels) in absolute terms. So I would take samples of the lower frequencies over time (not exactly sure how though, loudness might be involved in some way).

But anyway, google is your friend and I found Beat Detection On The Arduino. I did not read it.