Asked — Edited

Text To Servo Speech Engine

Here is a little project I have been working on with fellow forum member Bob Houston.... It was originally written by another forum member Louis Vazquez.... who really did a good job on this... I have tweaked it a little to try and make it more adaptable from project to project.... It works like sound servo, but using text to drive the servo instead of sound....

I have Luis' permission to post so here it is...

Textservotospeech.EZB

I have posted it to the cloud as well...


ARC Pro

Upgrade to ARC Pro

With Synthiam ARC Pro, you're not just programming a robot; you're shaping the future of automation, one innovative idea at a time.

Canada
#1  

Tanks Richard right on time to test Inmoov's head

#2  

Richard R and Luis Vazquez have done a great job writing these scripts to control a servo from text contain within a script. To get the text to control the servo you must input your text as; $sent $sent2 ControlCommand("Text Speech Engine", ScriptStart)

as in this example;


# This is an example script on how to drive the text to speech engine from other scripts

# Each word in $sent must have an "|" after it...
# You need both $sent and $sent2 formatted as bellow

$sent = "This|is|a|test|of|something|for|the|robot|to|say." #for speech engine
$sent2 = "This is a test of something for the robot to say." #actual speech for ezb or PC
ControlCommand("Text Speech Engine", ScriptStart)
ControlCommand("Speech Settings", SetVoiceRate, "Medium") #set speech rate to medium

You also need to have this script running as a Control Command;



#Text Speech Engine
# Author of the Speech engine
# Luis Vazquez



# Mouth servo is on D2
# speech settings - medium rate of speaking
say($sent2) # or sayEZB()

$a = 0

:loop
$value = split($sent , "|",$a)
# print($value)
$wordLenght = Cint(Length($Value))

$testlenght = Cint(Length($Value)) - 1
$b = 0
:wordloop
$wordletter = substring( $value,$b,1)
# print($wordletter)
$hasaccent = contains("a e i o u y", $wordletter)
IF ($hasaccent == 1)
  servo(d2 ,75)
  # sets how long mouth open on accent
  sleep(65)
  servo(d2, 90)
ELSE 
  # Sets how long delay between words
  sleep(75)
ENDIF 
$b = $b + 1
IF ($b != $wordLenght)
  goto(wordloop)
ENDIF 
$a = $a + 1
$testvar = substring($value,$testlenght ,1)
IF ($testvar != ".")
  goto(loop)
ENDIF

These scripts work great! You may have to adjust some of the timing and of course to the servo settings to meet your needs.

What is needed now is an easier way to enter the text. Hopefully, we will be able to make it work just by entering the text in Say() or SayEZB(). By"We", I mean the community, If you have any thoughts on this please post them. Thanks again Richard and Luis.

#3  

Just an added note... every sentence you use in $sent must end in a "." (period) or you get an error...

#4  

You can remove the "$sent" line by taking the "|" out;


$value = split($sent , "|",$a) 
#change to
$value = split($sent , " ",$a)

And no period at the end of a sentence is needed if this line is changed;


IF ($testvar != ".")
#change to
IF ($testvar != " ")

It works, however, it does show this error; 1/19/2015 4:52 PM - Error on line 13: Error splitting 'hello i am in move the robot.' with SplitChar: '' to field #1. Index was outside the bounds of the array.

#5  

Hello ,

After doing much testing I have an update to the Text speech movement.

It is basically doing the same thing with a major difference of when things get done.

as it is not each letter is evaluated in real time as the speech is being played aloud.

Problem is the more things ARC has going on (ie. Listening for speech , reading sensors , sending and receiving UART strings) the more out of whack the delays get and require adjusting.

This method will analyze the string to be said and turn it in to a string of commands to open or close the mouth.

Last it will say the words and execute the pre-compiled command string.

This will be more stable and should most always time the same.

Notes for modifying scripts.

New Hello World

change Line 1:

$sent = "This is a test of something for the robot to say."

Set the text to anything you want the computer to say and lip sync.

New Text Speech Engine

Set up the Mouth Server

Line 47 : Servo(D0,90) : Set D0 to the mouth servo you will use and 90 to the closed position of the mouth Servo

Line 55 : servo(D0,60) : Set D0 to the mouth servo you will use and 60 to the closed position of the mouth servo

Line 61 : Servo(D0,90) : Set D0 to the mouth servo you will use and 90 to the closed position of the mouth servo

Set up the Timing

Line 56 : Sleep(85) : time to leave servo in Mouth Open Positions before going to next char

Line 61 : Sleep(85) : time to leave servo in Mouth closed Positions before going to next char

Line 66 : Sleep(90) : time to leave servo in Mouth Closed Positions before next word

Speech out put

Line 44 : say($sent) : to send to Ezb4 user sayezb($sent)

Code for New Hello World


$sent = "This is a test of something for the robot to say."
ControlCommand("New Text Speech Engine", ScriptStart)

Code for New Text Speech Engine


#$sent = "This is a test of something to say"
$c = 0 
$SpeechLen = Length($sent)
$newWord = true 
$inchar = ""
$MoveText = ""

:buildloop

if ($c < $SpeechLen )
  $inchar = substring($sent , $c,1)
      if ($inchar == " ")
          $MoveText = $MoveText + "W"     
          $newWord = true 
          goto(exitbuildloop)
      else
        $wordletter = substring( $sent ,$c,1)
        $hasaccent = contains("a e i o u y", $wordletter)  
        if ($newWord)
            $hasaccent = true
            $newWord = false
        endif      
        if($hasaccent)
            $MoveText = $MoveText + "O"
        else
            $MoveText = $MoveText + "C"
        endif
      endif

:exitbuildloop
    $c =  $c + 1
    goto(buildloop)
endif


$c = 0 
#print($SpeechLen)
$moveLen = length($moveText)
$textstring = SubString($MoveText , $moveLen - 1,1)
      if ($textstring != "C")
          $MoveText = $MoveText + "C"
      endif 


say($sent)

Servo(D0,90) 

:moveloop
    $inchar = substring($moveText,$c,1)

        if ($inchar == "O")

            #Servo in Mouth Open Possition
            servo(D0,60)
            sleep(85)
        endif

        if ($inchar = "C")
            #Servo Mouth Closed Possition
            Servo(D0,90) 
            sleep(85)
        endif

        if ($inchar = "W")
            #Servo spacebetween words
            sleep(90) 
        endif
$c = $c + 1
if ($c < $moveLen)
goto(moveloop)
endif

I hope this helps out.

Luis Vazquez

Email Me

#6  

Thanks Luis.... It works great.... I was thinking last night about removing the "|" and just using a space to identify word separation... This would eliminate the need for 2 $sent ($sent2) strings... But you and Bob beat me to it... LOL

Thanks for the contribution on this....

Cheers Richard

#7  

I've uploaded this project to the cloud

look for project named

Text to Speech Engine V2

United Kingdom
#8  

I just scanned over it, am I right in thinking the text needs to be written twice, once with the | for splitting it up by word?

If that's the case, can it work dynamically, with RSS feeds etc.? Can't it be split from the space between words?

Also, would it not pay to use the Auto Position control for accurate mouth (and other facial features) movements depending on words used?

Like I said, only quickly scanned this so I apologise if the above has been mentioned before.