Implements a voice synthesiser using a single hardware PWM pin.
Note that you must add an amplifier board to drive the loud speaker. Do NOT connect a loudspeaker directly to your micro controller!!
This software works by changing the duty cycle of a 20kHz carrier frequency.
You can build a suitable amplifier yourself very cheaply without any SMD components and the board is just over an inch square:
I have uploaded my Eagle schematic and board files at http://www.societyofrobots.com/member_tutorials/node/216 but it would also be easy to use strip board if you don't want to make a PCB.
In brief: the amplifier input starts with R2 and C1 which filters out the 20kHz carrier frequency. C2 then passes the audio signal to the amplifier IC1. R3 is a trimmer to set the required output volume. R5 and LED1 provide a 'power on' indicator. The jumper allows you to select whether you are using the power from your robot board or from a separate battery.
Alternatively: there are some commercial boards available - just make sure the amplifier you use has a low-pass filter that filters out this 20kHz or add R2, C1 and C2 yourself.
If your robot goes outdoors then I suggest you use a Mylar speaker rather than a paper one - as they survive damp conditions without falling apart! Also make sure the speaker you purchase is easy to mount. If there are no screw holes on the speaker then you will need to hot glue it into place.
Finally some notes about speech quality:
1. In order to keep the software as small as possible then it uses 4 bit audio samples at a low sampling frequency. So don't expect the quality to be high fidelity - it's very retro!!
2. The quality is also effected by all the other interrupts that are going on depending on your application.
3. The logic to convert English text into sounds is quite complex and not always bullet proof
4. The output is better is the speaker is in some kind of box. Try cupping the loadspeaker in your hands to hear what I mean!
My website, http://webbot.org.uk has some example outputs as WAV files so that you can 'hear before you make'.
If you are using Project Designer then you can add the 'Text to Speech' synthesiser from the 'Audio' category of devices. You can also make it the destination for error messages and rprintf when generating the code for your project.
Otherwise you will need to call:
from your appInitHardware where H6 is the hardware PWM output pin of your choice.
Either way: the simplest method to output some text is:
sayText("Death to all humans");
However: this has some draw backs:
1. The compiler will store the string in both RAM and program memory.
2. The message is fixed
WebbotLib also provides a Writer - which means that you can use 'rprintf' to output variable information eg:
Writer old = rprintfInit(getSpeechWriter()); // Send rprintf to speech
rprintf("Death to all humans\n"); // String is only in program memory
rprintf("A number is %u\n",9); // Output a variable msg
rprintfInit(old); // Revert rprintf output to its original place
Note that when accessed via rprintf WebbotLib will queue up the text until it finds a '\n' at which point it will start talking.
Generating audio waveforms is difficult at the best of times and if your board is also talking to other sensors, motors and servos then it is even harder in a single tasking environment! I make no apologies for this.
So if the speech output is satisfactory until such time as you add all your other code then I suggest that you think about having a separate board just for speech. This board could receive the text via UART, I2C or SPI - all of which are supported using WebbotLib - and can then speak the text whilst your main board is going at full speed. Of course this board could be very simple, and cheap, such as the $50 Robot board from Society of Robots http://www.societyofrobots.com/robot_tutorial.shtml but using an ATMega328P rather than the ATMega8.
- speechInit - Initialise the speech system.
- sayText - Immediately speaks the English text.
- getPitch - Returns the current default pitch.
- setPitch - Changes the default pitch of the voice.
- getSpeechWriter - Obtain a Writer that can be used with rprintf commands.
speechInit(const IOPin* pin)
Initialise the speech system.
This should be called in appInitHardware and the single parameter is an IOPin that provides hardware PWM.
If you are using Project Designer then this is done for you auto-magically.
sayText(const char * src)
Immediately speaks the English text.
sayText("Death to all humans");
Returns the current default pitch.
Changes the default pitch of the voice.
Higher numbers will result in a lower voice and smaller number will give a higher voice.
Obtain a Writer that can be used with rprintf commands.
Although the sayText(const char * src) command is useful for writing out fixed pieces of text there are times when we want to output variable text. For example we may want to speak the value of a distance sensor - whose value is only known at runtime.
These values can be converted into text using the rprintf commands but we need to make sure that rprintf output is going to the speech sub-system rather than the default location which may a UART for data logging.
Assuming you are using WebbotLib to read the distance sensors then the distance will be returned in cm and can be dumped out by rprintf using the distanceDump command. So all we need to do is tell rprintf to 'speak' the result rather than to send it to where it is currently going:
// Tell rprintf to send output to speech, and remember the old destination
Writer old = rprintfInit(getSpeechWriter());
// Dump the sensor values to rprintf (ie speech)
// Make rprintf output go to original device