Doing a class on a Halloween Talking Skull class.. off loading the MP3 to the cool DFPlayer MP# module ($1 from AliExpress). Anyway.. I'm sampling the audio from the unit's extra DAC output.. into the Arduino A0.. am baselining "silence" so I can compensate for the ~2v DC component (plus it tends to drift).. that's all done.. but the hard part is a KISS method for sampling the "average amplitude" to use in a map function to drive the servo.. something like:
But it's not that simple.. low freq sample a sine wave and you'll get chaos.. anything but the avg amplitude.
Yes.. I've tried averaging sample values.. grabbing peaks, etc..
It still just looks like poor Mr. Skeleton is having a seizure.
I don't want ideas.. I've heard tons.. I want to know if anyone HAS a proven, seen it working, solution. [
I'm afraid that my knowledge of talking skulls is negligible, but It looks like you are attempting to use measured sound energy to control the movement of a 'robot jaw'.
If you don't like the DC component of the output from your audio device, use a 0.1uF capacitor in series with it.
edit
And a number of solutions which are claimed to work (although not necessarily in your very specific application area) . . .
A logarithmic type scale like dB might anyway be more suited to this activity because it is a more natural relationship between "sound volume" and jaw movement.
As an EE I tried an analog attempt first with rectifier capacitor network but couldn't get a good/usbale DC waveshape. I then figured any thing I was doing in circuit I could do in software, which is why I moved to a raw sampling/math route:
////// While DFPlayer _BUSY line is active(low), sample audio & move servo until not busy.
while(!digitalRead(dfBusy) == true ){
soundVal=analogRead(soundPin);
delay(10);
// This fairly quickly self-sets the soundMax and soundMin values (in case I need them)
if (soundVal > soundMax) {
soundMax=soundVal;
}
if (soundVal < soundMin) {
soundMin=soundVal;
}
////// Map Audio Level and move the mouth (various methods)
//soundVal = map(soundVal, soundMin, soundMax, mouthClosed, soundAmplitude);
//soundVal = map(soundVal, (soundMax-soundAmplitude), soundMax, mouthClosed, mouthOpened);
soundVal = map(soundVal, silenceVal, soundMax, mouthClosed, mouthOpened);
myServo.write(soundVal);
delay(200);
}
Before 6v6gt's suggestions.. I tried averaging a few samples, but next was going to try:
Averaging positive soundMax (above silenceVal) samples from a 9-10 sample array
Combine this with a sample separation of 300ms.. which would yield a 3Hz response rate
But I'll check out his links before I go down that path.
IMHO, it's unlikely you can get satisfying results even if someone writes the best ac-dc rectifier code, as there is a little correlation between articulation and speech. Better to write/ compose a special track for servo, than synchronously start both ,audio and servo.
Well I have a bit more experance with talking skulls.
A simple Envelope detector was used on this LED robot head speaking representation, looks not too bad:-
As to talking skulls I think you might find that the servos are not fast enough to make the jaw look anything more than superficially like it is talking. Meet Mulder
But it's not that simple.. low freq sample a sine wave and you'll get chaos.
You have to sample at greater than the Nyquist rate
Grumpy_Mike:
Well I have a bit more experance with talking skulls.
A simple Envelope detector was used on this LED robot head speaking representation, looks not too bad:-
Thanks Mike.. that's actually what I first tried in my first attack at solving in the analog domain. I just didn't know that was what it was called.. I might give that another try and take a closer look with the ole o-scope.
It would seem (though) that I could equally do it in the digital domain by ignoring any signal below the zero crossing (or DC offset in my case), and then only keeping the max values within a certain duration timing window.. thus.. roughly following the peaks (and maybe applying a log function to them).
You have to sample at greater than the Nyquist rate
I know for a fact this is not my problem.. as even if a sampled at 5x the max frequency and ignoring negative lobes.. with a single loud tone.. I would still be grabbing values between the peaks and nulls.. thus resulting the seemingly random mouth movements (or at best, a beat frequency mouth movement). I'll make sure that I'm at least 2.1x my max sample frequency.. but that's not what is causing my issues... especially since now I'm only using soundMax values.
But thanks for the ideas.. I'll try the sliding max window to attempt to estimate an analog volume envelope (first), and if that doesn’t cut it.. then try out a simple analog envelope detector.
as even if a sampled at 5x the max frequency and ignoring negative lobes.. with a single loud tone.. I would still be grabbing values between the peaks and nulls.. thus resulting the seemingly random mouth movements (or at best, a beat frequency mouth movement).
Yes 5X is not going to cut it either for a maximum over a single cycle. The more samples you can gather looking for a maximum the more likely you are to get close to the true one. You could increase the sample rate of the analogRead function, see reply #2 of this very old thread:- http://forum.arduino.cc/index.php?topic=6549.0
Then you could average a succession maximum readings to get a value to use to set the servo.
But personally I think an envelope follower / detector is simpler.