HeadBot Example and Starting Code

HeadBot Example and Starting Code

 

Update: 11/4/2015 - See bottom, added some comments about some minor tweaks I've done.

So Box Head and DRHead are done and fun but how does it all happen? It’s really simple when you look at it. The PC runs some simple voice recognition stuff in VB.net and the Arduino listens for commands from the PC and responds or does it’s own thing like blinking, etc.

Here’s how I’m doing this at least but I’m sure there are many other ways of doing the same thing. i think I left enough examples in the code to see how it works and how to add your own options. the code should allow for sending commands to the microcontroller, getting text and RSS info from the web, and just making general conversation… albeit very limited conversation.

Sorry I tried to make this short and sweet but if you already know how most of this works just get the code and build your bot. If not there are a few steps that may or may not be helpful here.

The PC Side

Get VB.net 2008 installed

The PC side is a VB.net Visual Studio 2008 (remember Box Head and DRHead are running on old XP laptops) and your normal Arduino stuff. It will work on Win7 by uncommenting a few things or re-commenting a few things in the enable area. It’s pretty obvious that Microsoft wants to get people to move along off the old development, and other old products, and on to the new but I’m still an old hack BASIC coder so I like the old VB.net 2008 version. You cannot find the download on the main MS site anymore and if you find a small “setup” program it would work for me as if the main download MS server is gone.

You may well be able to load this up and use it in a new version for VB Express, I just haven’t tried so far. BUT I DID find this ISO link and used it to download and burn a VB.net 2008 instllation disc. Actually Visual Studio 2008 but we only need VB.net to run this. https://go.microsoft.com/fwlink/?LinkId=104679 should give you an approximate 800mb download for the ISO. Burn it to an install disc and install the VB portion. This should be a setup file under the VBExpress folder. I do NOT want to help MS with the “experience” … especially since there is no experience left for this product so I uncheck that box. I also uncheck the MSDN Express Library and the Microsoft SQL Server 2005 Express install… not needed. Let the install run and keep reading… The install takes a while at least on my old machines.

Get the SAPI 5.x

I THINK you will need this but you might try it without the install. I do not think it will hurt anything one way or another but I know it’s needed on Win XP systems. This appears to still be found on the MS sites located here: https://www.microsoft.com/en-us/download/details.aspx?id=10121 - Click the DOWNLOAD button to get the options. You really only need the “SpeechSDK51.exe” and maybe the “msttss22l.exe” files I think unless you may want other languages but I haven’t messed with that.

eSpeak Install (Optional)

If you want to use or play with the eSpeak option then download and install eSpeak. I default the VB code to use eSpeak in the C:\eSpeak folder so either create that and copy the files in the /command_line folder in the eSpeak install or change the starting point in the speaking subroutine. you can actually switch between the MS and eSpeak voice options using voice commands if you want.

Getting the Code Into VB

Create you a new VB project as a Windows Form Application, give it a name at the bottom and click on through. Get into the Form1 design area by double clicking the Form1 and copy/paste the code here for the VB side. You’ll have some errors if you try to run (debug)  but add the form fields and button like the image shows here to get past them and just work them one at a time. Any errors should be limited to the form fields as the code works for me with the right fields on the form. (No I’m not good a standardized labeling so if you want to fix that you can do that now too.)

You will also need to add the System.Speech .net object and maybe the Microsoft Speech Object Library COM reference from my experience and what I’ve seen online so add that under the Project / Add Reference menu items. Make sure the .NET tab is selected and scroll down to the System.Speech item and click OK. Then if you want add the Speech Object Library under the COM tab.Form Fields

Now go back to the Form1 design and add the following fields from the image. They should be TextHeard multiline textbox, LastSaid multiline textbox, LastCommandSent multiline textbox, lblStatus label, lblVoiceStatus label, cmbPorts combo box, cmbBitRate combo box, and Button1 button. You can update the text on the button to Open, OpenCom, Connect, Screw It, or whatever you want.

Remember you DO have to have a microphone or some type of audio input device to use voice recognition. Seems silly BUT I was stumped for a bit when I tested on a new machine without a mic instead of a laptop with built in mic before. Yeah, I’m stupid. Also make sure you run through the basic speech recog mic setup in the Control panel to make sure things are working. The Win7+ speech recog stuff has to work before this will work. You will yell less at your robot if you do this, I promise.

Also make sure you have at least ONE Serial COM port to test the code as it doesn’t expect a machine with nothing in it as you are already writing code for microcontrollers so you have COM ports.. right?

There are a few variables you can use once the code is runnable including the Robot's name, what you want he/she/it to call you when you wake it up if you leave that in, which COM port you want to default open, etc. Read the comments and it should make sense. The code defaults to the Microsoft voices but you can change that to eSpeak by flipping that variable in the DIM area. Or use the “Please use the eSpeak voice” command.

You should be able to turn OFF the GetComResponse flag and run the code WITHOUT a microcontroller hooked up. That just polls the micro for a response after sending a command. If you are getting slow choppy responses you are likely waiting for the com data timeout and not sending a blip back to the VB app.

The Arduino Side

I am not going to discuss much here, it’s Arduino so if you’re using an Arduino as your animation driver then you need to know a bit about it already. The basic code is included that should work with the VB code and allow basic left/right and up/down head movement, eye blinking using RGB or single LEDs, and driving a jaw animation either by servo or by LED… or both if you so desire... That would actually be kind of cool but I haven’t done that. Put an LED inside the mouth so it blinks as the jaw opens… hmmm...

If you change up the pin layout, which may be a good idea, make sure you make the changes to the Arduino code to adjust for it. Otherwise just read through the code and find all my bugs for me, fix them, and republish please. :-)

Setting default Microsoft voices

You can setup the default MS voice to use in the Control Panel / Speech area. Windows 7 is limited to the Anna voice for the most part I believe. One may be able to parse the SAPI5 voices and make a selection in the code for them. I’ve done that in an old VB6 app but never looked at the option here since I’ve only really run this under XP.

Limitations and Information

Remember, as this is designed so you have to use the pretty much the exact words to get the command recognized. You also have to have the ExACt case in the IF statement as is in the grammar array or it generally won’t work. I could have UCASED things etc or made the process better but I didn’t.

Also remember everything is hard coded here so you can’t really add commands on the fly. A well written app would have a front end to add the phrase, command to send to the micro, field for what we are supposed to do such as RSS, URL, Speak, or multiple variations thereof, and so on. For my purposes I just run it all in “debug” mode as I’m always tweaking something one way or another.

One last thing, be nice, I’m a hack coder that have somehow made an IT career spanning from PDP 11/34’s through today’s virtual everything and do code web, script and automation at the gov I work for. Just saying you are not going to see super nice, structured, professional code. But I have fun anyhow. :-)

 

Closing:

So give it a try, share what you've done and just have fun with a Head Bot on your desk, kitchen bar, or on your mobile robot. Which reminds me, I need to get a bluetooth speaker and mic and get my BT serial device working so my next Head Bot is a Mobile Head Bot.

Resources:

Visual Studio 2008 ISO Download

https://go.microsoft.com/fwlink/?LinkId=104679

 

SAPI 5.x SDK

https://www.microsoft.com/en-us/download/details.aspx?id=10121

 

eSpeak text to speech

http://espeak.sourceforge.net/

 
Source Code VB.Net
 
'** HeadBot - Copied from DRHead and Box Head from long ago
'** Just the basic frame but should work for the most part
'** V1.00 - Stephen W Nolen / Protowrxs 2015


'** May not need all these - they have been added over time
Imports System.Speech.Recognition
Imports System.Speech.Synthesis
Imports System.Collections.ObjectModel
Imports System.Net.WebClient
Imports System.Threading
Imports System.Globalization
Imports System
Imports System.IO.Ports
Imports System.Net
Imports System.Xml


'** Load up the main form and take off
'** There are a few variables you may want to adjust
'** 
Public Class Form1
    Dim UsingWin7 As Boolean = True             '** I'm sure this can be figured out in code BUT for now...
    Dim RobotName As String = "Robot"           '** Give  your bot a simple but unique name for best results
    Dim YourName As String = "My Great Creator"       '** What you want your HeadBot to call you when you wake him up
    Dim MyComPortIndex As Integer = 0           '** Change this to the pull down index (0-??) for your default port
    Dim HeadBotBirthDay As Date = "10/31/2015"  '** Set to the date your bot was "born"
    Dim WaitForSpeech As Boolean = True         '** ONLY needed for MS voices if you are animated a jaw or mouth, 

otherwise leave as false

    Dim myComPort As New SerialPort             '** Com port for communications
    Dim GetComResponse As Boolean = False       '** IF you want to get/display responses from Arduino then TRUE
    '** If TRUE and nothing there you get delays waiting for data
    Dim InBoundData As String                   '** From MCU
    Dim myspeaker As New SpeechSynthesizer      '** Speech synth output
    Dim ListenFlag As Boolean                   '** This determines if he listens for everything or just Hello 

'Robotname'
    Dim webClient = New System.Net.WebClient()  '** Used for getting data from / to the web
    Dim Mytext As String                        '** General text holder
    Dim LastContactTime As Date                 '** Last time he heard / did something for future mood swings
    Dim StartTime As Date                       '** When wer started up for general "I've been up since" stuff
    Dim CurrentHeard As String                  '** text from recognizer to use
    Dim PreviousHeard As String                 '** previous text from last heard for trying to repeat things that didn't 

work
    Dim AnimateJaw As Boolean = True            '** starts out ON but you can change by saying please use your slack jaw


    Dim eSpeak As Boolean = False             '** COMMENT out to use MS voice
    Dim SpeechPitch As Integer = 50              '** This is for the eSpeech engine only
    Dim SpeechPitchNormal As Integer = SpeechPitch
    Dim OldSpeechPitch As Integer
    Dim SpeechSpeed As Integer = 175
    Dim SpeechSpeedNormal As Integer = SpeechSpeed
    Dim OldSpeechSpeed As Integer

    Dim MSSpeechSpeed As Integer = 1            '** This is for the MS Speech engines and only used if eSpeak if FALSE
    Dim MSSpeechSpeedNormal As Integer = MSSpeechSpeed     '** Saving this form "Normal" speech return

    '** Setup recogniser & grammar
    Dim recog2 As New SpeechRecognizer
    Dim recog As New SpeechRecognitionEngine
    Dim gram As Grammar


    '** Setup the events handler for recognition
    Public Event SpeechRecognized As EventHandler(Of SpeechRecognizedEventArgs)
    Public Event SpeechRecognitionRejected As EventHandler(Of SpeechRecognitionRejectedEventArgs)

    '** word list - This the list of words/phrases we are recognizing.
    '** We would like to move this to a file so we can add things on the fly like names, etc
    Dim wordlist As String() = New String() {RobotName, "Hello " & RobotName, "Goodbye " & RobotName, "How are you 

doing", _
                                             "Please Look to the Left", "please look to the right", "Please Look 

Forward", _
                                             "Please Look Middle", "Please look up", "Please look down", _
                                             "Whats the latest news", "What is your name", "Who are you", _
                                             "What time is it", "Thats incorrect", "its ok " & RobotName, _
                                             "Are you happy", "Whats your age", "How old are you", _
                                             "How many days until Christmas", "How many days until halloween", _
                                             "Whats new at cool kids robots", _
                                             "You look handsome", "That didn't work", "Thank you " & RobotName & "", _
                                             "Please speak lower", "Please speak higher", "Please speak normal", _
                                             "Please speak faster", "Please speak slower", _
                                             "Please animate your jaw", "Please use your slack jaw", _
                                             "Please give me a wink", "Please use e speak voice", "Please use micro soft 

voice", _
                                             "Please use your blue eyes", "Please use your red eyes", "Please use your 

green eyes", _
                                             "Please use your red mouth", "Please use your green mouth", "Please use your 

blue mouth"}
    '** Word recognised event
    Public Sub recevent(ByVal sender As System.Object, ByVal e As RecognitionEventArgs)

        '** If we recongized a word/phrase then turn off recog so we don't hear ourself

        'recog.Enabled = False               '** If using WinXP use this
        recog.RecognizeAsyncCancel()        '** If using Win7/8/etc use this

        If (e.Result.Text = "Hello " & RobotName) Then      '** This is the wake up call that turns on the listen flag
            SendCommand("F")                                '** Start out looking forward
            SendCommand("H")                                '** This is the basic "head wobble" command to the MCU

            SayIt(RandomInterjection("PREFIX") & ", Hello " & YourName & "!")                       '** and say Hi
            ListenFlag = True
        End If

        If ListenFlag Then                              '** If we are in LISTEN MODE then we process

            '** If we are listening and heard something we understand then we start processing
            CurrentHeard = e.Result.Text                '** save the new heard value
            PreviousHeard = lblVoiceStatus.Text         '** save the previous heard in case we need to repeat

            '** If the command wasn't done you can use that didn't work to have him/her repeat the last command
            '** we just load up the CurrentHeard with the previous heard phrase for processing
            '** Problem is it saves this off as that didn't work multiple times doesn't work.. oh the irony...
            If e.Result.Text = "That didn't work" Then
                SayIt(RandomInterjection("PREFIX") & ", let me try it again then.")
                CurrentHeard = PreviousHeard
                TextHeard.Text = CurrentHeard & vbCrLf & TextHeard.Text
            End If

            lblVoiceStatus.Text = CurrentHeard         '** Update the form label so we know what was said
            TextHeard.Text = CurrentHeard & vbCrLf & TextHeard.Text

            '** Handle the results commands here
            If (CurrentHeard = RobotName) Then
                SendCommand("H")
                SayIt("Yes?")

            ElseIf (CurrentHeard = "Please use e speak voice") Then
                eSpeak = True
                SayIt(RandomInterjection("PREFIX") & ", I should now be using e speak voice")

            ElseIf (CurrentHeard = "Please use micro soft voice") Then
                eSpeak = False
                SayIt(RandomInterjection("PREFIX") & ", I should now be using my micro soft voice")

            ElseIf (CurrentHeard = "What is your name") Or (CurrentHeard = "Who are you") Then
                SendCommand("H")
                SayIt("My name is " & RobotName & ", but you can call me " & RobotName & ".")

            ElseIf (CurrentHeard = "Please give me a wink") Then
                If CInt(Math.Ceiling(Rnd() * 100)) > 50 Then
                    SendCommand("W")
                    SayIt("Hey there sexy thang.")
                Else
                    SendCommand("w")
                    SayIt("Well, I Hope I did that correctly.")
                End If

            ElseIf (CurrentHeard = "Thank you " & RobotName) Then
                SendCommand("H")
                SayIt("You're welcome")

            ElseIf (CurrentHeard) = "Your welcome" Or (CurrentHeard = "Your right") Then
                SendCommand("H")
                SayIt("Thank you")

            ElseIf (CurrentHeard = "Please animate your jaw") Then
                SendCommand("H")
                AnimateJaw = True
                SayIt(RandomInterjection("POSITIVE") & ". My jaw should now animate when speaking.")

            ElseIf (CurrentHeard = "Please use your slack jaw") Then
                SendCommand("H")
                AnimateJaw = False
                SayIt(RandomInterjection("PREFIX") & ". My jaw is no longer animated. Feels better to my servo even.")

            ElseIf (CurrentHeard = "Please Look Up") Then
                '** If your bot CAN look up then change this
                SayIt("Ok")
                SendCommand("U")

            ElseIf (CurrentHeard = "please look to the right") Then
                SendCommand("R")
                SayIt("Ok")

            ElseIf (CurrentHeard = "Please Look Down") Then
                '** If your bot CAN look down then change this
                SayIt("Ok")
                SendCommand("D")

            ElseIf (CurrentHeard = "Please Look to the Left") Then
                SendCommand("L")
                SayIt("Ok")

            ElseIf (CurrentHeard = "Please Look Forward") Then
                SendCommand("F")
                SayIt("Ok")

            ElseIf (CurrentHeard = "Please Look Middle") Then
                SendCommand("M")
                SayIt("Ok")
            ElseIf (CurrentHeard = "Please look up") Then
                SendCommand("U")
                SayIt("OK")
            ElseIf (CurrentHeard = "Please look down") Then
                SendCommand("D")
                SayIt("OK")

            ElseIf (CurrentHeard = "Please speak higher") Then
                SendCommand("H")
                SayIt("Ok")
                SpeechPitch = SpeechPitch + 25
                If SpeechPitch > 200 Then SpeechPitch = 200
                SayIt(RandomInterjection("POSITIVE") & ", I am now speaking a little higher.")
                If SpeechPitch >= 100 Then
                    SayIt("Seriously, this feels really ackward talking like this.")
                End If

            ElseIf (CurrentHeard = "Please speak lower") Then
                SendCommand("H")
                SayIt("Ok")
                SpeechPitch = SpeechPitch - 10
                If SpeechPitch < 1 Then SpeechPitch = 1
                SayIt("I am now speaking a little lower.")

            ElseIf (CurrentHeard = "Please speak faster") Then
                SendCommand("H")
                SayIt("OK")
                If eSpeak Then
                    SpeechSpeed = SpeechSpeed + 25
                Else
                    MSSpeechSpeed = MSSpeechSpeed + 1
                    myspeaker.Rate = MSSpeechSpeed
                End If

                SayIt("I am now speaking a little faster.")
                If (SpeechSpeed > 250) Or (MSSpeechSpeed > 5) Then
                    SayIt("Gee, I do not see how you understand what I am saying this fast.")
                End If

            ElseIf (CurrentHeard = "Please speak slower") Then
                SendCommand("H")
                SayIt("OK")
                If eSpeak Then
                    SpeechSpeed = SpeechSpeed - 25
                Else
                    MSSpeechSpeed = MSSpeechSpeed - 1
                    myspeaker.Rate = MSSpeechSpeed
                End If
                SayIt(RandomInterjection("POSITIVE") & ", I am now speaking a little slower")
                If (SpeechSpeed < 100) Or (MSSpeechSpeed < -5) Then
                    SayIt("Wow, you must be really dumb to need me to speak this slow at rate " & MSSpeechSpeed)
                End If

            ElseIf (CurrentHeard = "Please speak normal") Then
                SendCommand("H")
                SayIt("Ok")
                If eSpeak Then
                    SpeechPitch = SpeechPitchNormal
                    SpeechSpeed = SpeechSpeedNormal
                Else
                    MSSpeechSpeed = MSSpeechSpeedNormal
                    myspeaker.Rate = MSSpeechSpeed
                End If
                SayIt("Ahh, good, I am now speaking my normal voice.")

            ElseIf (CurrentHeard = "Tell me the weather forecast") Or (CurrentHeard = "How is the weather") Then
                SendCommand("H")
                SayIt(RandomInterjection("WAIT"))
                SayWeather()

            ElseIf CurrentHeard = "Whats new at cool kids robots" Or CurrentHeard = "Whats new at C K R" Then
                SendCommand("H")
                SayIt("Just a second, getting cool stuff")
                ReadRss("http://www.coolkidsrobots.com/rss.xml")

            ElseIf (CurrentHeard = "Whats the latest news") Then
                SendCommand("H")
                SayIt(RandomInterjection("WAIT"))
                'ReadRSS("http://news.yahoo.com/rss/")
                ReadRss("http://news.yahoo.com/rss/us")

            ElseIf (CurrentHeard = "How are you doing") Then
                SendCommand("H")

                SayIt(RandomInterjection("POSITIVE") & "I'm doing fine, just stuck here on my stand.")
                SayIt("It has been " & DateDiff("s", LastContactTime, Now()) & " seconds since someone talked to me")
                SayIt("I've been active for " & DateDiff("s", StartTime, Now()) & " seconds as well.")

            ElseIf (CurrentHeard = "What time is it") Then
                SendCommand("H")
                SayIt("Looks like the current time is " & TimeOfDay() & " to me.")


            ElseIf (CurrentHeard = "What is the date") Then
                SendCommand("H")
                SayIt("Looks like the current date is " & DateString & " to me.")

            ElseIf (CurrentHeard = "Thats incorrect") Or (CurrentHeard = "Thats pretty bad") Or (CurrentHeard = "Thats 

not funny") Then
                SendCommand("D")
                SayIt("Sorry about that...")

            ElseIf (CurrentHeard = "its ok " & RobotName) Or (CurrentHeard = "Good job") Or (CurrentHeard = "That is 

correct") Or (CurrentHeard = "That worked") Then
                SendCommand("H")
                SayIt("Good, thank you.")

            ElseIf (CurrentHeard = "Are you happy") Then
                SendCommand("H")
                SayIt("Usually I am, but sometimes I get bored just sitting here.")

            ElseIf (CurrentHeard = "Whats your age") Or (CurrentHeard = "How old are you") Then
                SendCommand("H")
                SayIt(RandomInterjection("PREFIX") & ", I was created around " & HeadBotBirthDay & " so I guess I am 

about " & DateDiff("d", HeadBotBirthDay, Now()) & " days old.")

            ElseIf (CurrentHeard = "How many days until Christmas") Then
                SendCommand("H")
                SayIt(RandomInterjection("WAIT") & ".")
                SayDateDiff("Christmas")

            ElseIf (CurrentHeard = "How many days until halloween") Then
                SendCommand("H")
                SayIt("Cool, that is my favorite holiday!")
                SayDateDiff("Halloween")

            ElseIf (CurrentHeard = "Please use your red eyes") Then
                SendCommand("r")
                SayIt(RandomInterjection("PREFIX") & ", My eyes should now be red!")

            ElseIf (CurrentHeard = "Please use your blue eyes") Then
                SendCommand("b")
                SayIt(RandomInterjection("PREFIX") & ", My eyes should now be blue?")

            ElseIf (CurrentHeard = "Please use your green eyes") Then
                SendCommand("g")
                SayIt(RandomInterjection("PREFIX") & ", My eyes should now be green!")

            ElseIf (CurrentHeard = "Please use your red mouth") Then
                SendCommand("1")
                SayIt(RandomInterjection("PREFIX") & ", my mouth should now be red.")

            ElseIf (CurrentHeard = "Please use your green mouth") Then
                SendCommand("2")
                SayIt(RandomInterjection("PREFIX") & ", my mouth should now be green. Kind of taste like grass.")

            ElseIf (CurrentHeard = "Please use your blue mouth") Then
                SendCommand("3")
                SayIt(RandomInterjection("PREFIX") & ", my mouth should now be a smooth blue.")

            ElseIf (CurrentHeard = "Goodbye " & RobotName) Then
                SendCommand("H")
                SendCommand("R")
                SayIt(RandomInterjection("PREFIX") & ", nice talking with you. Good bye")
                SendCommand("G")
                ListenFlag = False
            End If

            '** Save off the last contact date / time here for future reference
            LastContactTime = Now()

        End If

        recog.RecognizeAsync(RecognizeMode.Multiple)    '** If using WIN7 use this
        'recog.Enabled = True              '** If using WinXP use this

    End Sub

    ' recognition failed event
    Public Sub recfailevent(ByVal sender As System.Object, ByVal e As RecognitionEventArgs)
        lblVoiceStatus.Text = "Heard but not understood"
        '**SayIt("Sorry, I did not understand you.")    '** This isn't useful, just keeps saying it over and over
        lblVoiceStatus.Text = "Listening"
    End Sub

    ' form initialisation
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        ' need these to get British English rather than default US??
        '       Thread.CurrentThread.CurrentCulture = New CultureInfo("en-GB")
        '        Thread.CurrentThread.CurrentUICulture = New CultureInfo("en-GB")
        ' convert the word list into a grammar

        Dim words As New Choices(wordlist)
        gram = New Grammar(New GrammarBuilder(words))
        recog.LoadGrammar(gram)

        ' add handlers for the recognition events
        AddHandler recog.SpeechRecognized, AddressOf Me.recevent
        AddHandler recog.SpeechRecognitionRejected, AddressOf Me.recfailevent

        '** Win XP recog enabler
        'recog.Enabled = True


        '** Win 7+ recog enabler
        recog.SetInputToDefaultAudioDevice()
        recog.RecognizeAsync(RecognizeMode.Multiple)

        '** Load up the speech output
        myspeaker.Rate = MSSpeechSpeed
        myspeaker.Volume = 100

        StartTime = Now()           '** Log program start time for speaking

        InitializeForm()            '** Open up /init out display form
        OpenComPort()

        '** Just send a head move command to show he/she/it is alive
        SendCommand("H")

        '** You can say any opening comments here
        SayIt("Hello, I am " & RobotName & ".")

    End Sub


    '** Open up the COM port
    '** This auto opens to the index in the variable at the top but you can select diff port if needed on the form
    Sub OpenComPort()

        Try
            ' Get the selected COM port's name from the combo box.
            If myComPort.IsOpen Then
                myComPort.Close()
            End If
            If Not myComPort.IsOpen Then
                myComPort.PortName = cmbPorts.SelectedItem.ToString

                ' Get the selected bit rate from the combo box.

                If cmbBitRate.SelectedIndex > 0 Then
                    myComPort.BaudRate = CInt(cmbBitRate.SelectedItem)
                End If

                ' Set other port parameters.

                myComPort.Parity = Parity.None
                myComPort.DataBits = 8
                myComPort.StopBits = StopBits.One
                myComPort.Handshake = Handshake.None

                myComPort.ReadTimeout = 3000
                myComPort.WriteTimeout = 5000

                '** This is the long term plan but need to research the solution
                ' AddHandler myComPort.DataReceived, AddressOf DataReceivedHandler

                ' Open the port.

                myComPort.Open()

            End If

        Catch ex As InvalidOperationException
            MessageBox.Show(ex.Message)
            SayIt(ex.Message)

        Catch ex As UnauthorizedAccessException
            MessageBox.Show(ex.Message)
            SayIt(ex.Message)

        Catch ex As System.IO.IOException
            MessageBox.Show(ex.Message)
            SayIt(ex.Message)

        End Try
    End Sub

    '** Load up our form the first time through and setup a few things
    Sub InitializeForm()

        Dim bitRates(9) As Integer
        Dim nameArray() As String

        ' Find the COM ports on the system.
        nameArray = SerialPort.GetPortNames
        Array.Sort(nameArray)

        ' Fill a combo box with the port names.
        cmbPorts.DataSource = nameArray
        cmbPorts.DropDownStyle = ComboBoxStyle.DropDownList

        ' Select a default port.
        '** Change this index to your default value to avoid resetting - see top variables
        cmbPorts.SelectedIndex = MyComPortIndex

        'Bit rates to select from.
        bitRates(0) = 300
        bitRates(1) = 600
        bitRates(2) = 1200
        bitRates(3) = 2400
        bitRates(4) = 9600
        bitRates(5) = 14400
        bitRates(6) = 19200
        bitRates(7) = 38400
        bitRates(8) = 57600
        bitRates(9) = 115200

        'Place the bit rates in a combo box.
        cmbBitRate.DataSource = bitRates
        cmbBitRate.DropDownStyle = ComboBoxStyle.DropDownList

        ' Select a default bit rate.
        cmbBitRate.SelectedItem = 9600

        Me.Text = RobotName
    End Sub


    Private Sub SendCommand(ByVal command As String)

        Dim response As String

        Try

            'myComPort.WriteLine(command)   '** Use this if your micro controller code is waiting for a return at the end
            myComPort.Write(command)

            '** If we WANT to get responses from the micro then enable Getcomresponse
            '** we get delays waiting for response otherwise
            If GetComResponse Then
                '**response = myComPort.ReadLine    '** use this if you are sending a full CR/LF at the end of your 

response
                response = myComPort.ReadByte
                lblStatus.Text = response           '** This is currently the ascii value of the return it appears, I 

haven't used it really
            Else
                lblStatus.Text = "OFF"
            End If

            '** this is here to allow for some responses based on return from the micro but never implemented
            'Select Case response
            '
            '               Case "0"
            '
            '          lblStatus.Text = "LED 1 is OFF"
            '
            '             Case "1"
            '
            '        lblStatus.Text = "LED 1 is ON"
            '
            '   Case Else
            '
            'End Select

            LastCommandSent.Text = command & vbCrLf & LastCommandSent.Text


        Catch ex As TimeoutException
            lblStatus.Text = "I did not get a response."
            'MessageBox.Show(ex.Message)

        Catch ex As InvalidOperationException
            'MessageBox.Show(ex.Message)
            lblStatus.Text = "Sorry, I have an error."

        Catch ex As UnauthorizedAccessException
            'MessageBox.Show(ex.Message)
            lblStatus.Text = "I cannot access that information."

        End Try
    End Sub


    Private Sub Label1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lblStatus.Click

    End Sub

    '** This is for Tweeting information
    '** I actually use TweetyMail so you would need an account for that along with the code to send an email
    '** I can include that if anyone is interested
    '** Updated the pathing as needed though
    Private Sub Tweet(ByVal MyTweet)
        Dim start As New ProcessStartInfo
        start.FileName = "C:\WINDOWS\system32\cscript.exe"
        start.Arguments = "C:\Tweet.vbs " & Chr(34) & MyTweet & Chr(34)
        start.UseShellExecute = False
        start.RedirectStandardOutput = True
        start.RedirectStandardError = True

        Dim myproc As New Process
        myproc.StartInfo = start
        myproc.Start()
        Dim so As System.IO.StreamReader
        Dim se As System.IO.StreamReader
        se = myproc.StandardError
        so = myproc.StandardOutput
        myproc.WaitForExit()

    End Sub
    '** This is an external VBS as well that is not included but you can write your own
    '** OR add code here to read and parse the information
    Private Sub SayWeather()
        Dim start As New ProcessStartInfo
        start.FileName = "C:\WINDOWS\system32\cscript.exe"
        start.Arguments = "C:\Coding\VBScript\weather.vbs"
        start.UseShellExecute = False
        start.RedirectStandardOutput = True
        start.RedirectStandardError = True

        Dim myproc As New Process
        myproc.StartInfo = start
        myproc.Start()
        Dim so As System.IO.StreamReader
        Dim se As System.IO.StreamReader
        se = myproc.StandardError
        so = myproc.StandardOutput
        myproc.WaitForExit()
        '        MsgBox(so.ReadToEnd)
        '       MsgBox(se.ReadToEnd)
    End Sub
    '** This just fires off the POST to the URL in question and gets the results
    '** This is where my Home Automation System takes commands or status request and writes text back to say as desired
    Private Sub CheckURL(ByVal MyCommand)
        Dim result As String
        Try
            result = webClient.DownloadString(MyCommand)
        Catch
            result = "Sorry, could not get the information"
        End Try

        SayIt(result)

    End Sub

    '** the main speaking sub. Just takes a string and talks
    '** If using eSpeak then fires it off, otherwise the MS version
    '** need a waiting for piece for MS to animate things though???

    Private Sub SayIt(ByVal MyString)

        If eSpeak Then

            

'************************************************************************************************************************

****
            '** Main talking sub for eSpeak.
            '** After installing I copied the command line folder files to C:\eSpeck to make it easier to find
            '** But you can point it anywhere you need to.
            Dim start As New ProcessStartInfo
            start.FileName = "C:\espeak\espeak.exe"
            start.Arguments = " -p " & SpeechPitch & " -s " & SpeechSpeed & " " & Chr(34) & MyString & Chr(34)

            start.UseShellExecute = False
            start.RedirectStandardOutput = True
            start.RedirectStandardError = True

            Dim myproc As New Process
            myproc.StartInfo = start
            myproc.Start()
            Dim so As System.IO.StreamReader
            Dim se As System.IO.StreamReader
            se = myproc.StandardError
            so = myproc.StandardOutput

            '** Just sends whatever command you want to the micro to act like it's talking
            '** I have either animating action with the T/t or just open/close jaw with J/j
            If AnimateJaw Then
                SendCommand("T")
            Else
                SendCommand("J")
            End If

            myproc.WaitForExit()

            If AnimateJaw Then
                SendCommand("t")
            Else
                SendCommand("j")
            End If

        Else
            '** You will have to do something different here to get the status of the speaker?
            If AnimateJaw Then
                SendCommand("T")
            Else
                SendCommand("J")
            End If

            myspeaker.Speak(MyString)
            If WaitForSpeech Then
                Do Until myspeaker.State = SynthesizerState.Ready
                    '** Just waiting for speech to complete
                Loop
            End If

            If AnimateJaw Then
                SendCommand("t")
            Else
                SendCommand("j")
            End If

        End If

        LastSaid.Text = MyString & vbCrLf & LastSaid.Text
    End Sub


    Private Sub ReadRss(ByVal strURL As String)
        '** Reads the <TITLE> fields out of the provided RSS feed.
        '** Seems to usually work but may need tweaking for other types
        Dim rssDoc = New XmlDocument()
        Try
            rssDoc.Load(strURL)

            Dim rssItems As XmlNodeList = rssDoc.SelectNodes("rss/channel/item")

            Dim title As String = ""
            Dim link As String = ""
            Dim upperlimit As Integer = rssItems.Count
            If upperlimit > 5 Then
                upperlimit = 5
            End If
            If upperlimit > 0 Then
                Dim i As Integer = 0
                While i < upperlimit
                    Dim rssDetail As XmlNode
                    rssDetail = rssItems.Item(i).SelectSingleNode("title")
                    title = rssDetail.InnerText
                    SendCommand("H")
                    SayIt("Headline " & i + 1)
                    SayIt(title)

                    rssDetail = rssItems.Item(i).SelectSingleNode("link")
                    link = rssDetail.InnerText
                    i += 1
                End While
            End If
        Catch ex As Exception
            SayIt("Sorry, could not connect to the Internet")

        End Try

    End Sub

    '** This is supposed to read the full story or link but never really used it
    Private Sub ReadFullRss(ByVal strURL As String)
        Dim rssDoc = New XmlDocument()
        Try
            rssDoc.Load(strURL)

            Dim rssItems As XmlNodeList = rssDoc.SelectNodes("rss/channel/item")

            Dim title As String = ""
            Dim link As String = ""
            Dim upperlimit As Integer = rssItems.Count
            If upperlimit > 5 Then
                upperlimit = 5
            End If
            If upperlimit > 0 Then
                Dim i As Integer = 0
                While i < upperlimit
                    Dim rssDetail As XmlNode
                    rssDetail = rssItems.Item(i).SelectSingleNode("title")
                    title = rssDetail.InnerText
                    SayIt("Headline " & i + 1)
                    SayIt(title)

                    rssDetail = rssItems.Item(i).SelectSingleNode("link")
                    link = rssDetail.InnerText
                    i += 1
                End While
            End If
        Catch ex As Exception
            SayIt("Sorry, could not connect to the Internet.")
        End Try
    End Sub

    '** can be used to play any .wav on the local machine if you want sound effects etc
    Private Sub PlayWav(ByVal WavFile)
        Dim Sound As New System.Media.SoundPlayer()

        Sound.SoundLocation = WavFile  'ex.: c:\mysound.wav  
        Sound.Load()
        Sound.Play()
    End Sub

    Private Sub DataReceivedHandler(ByVal sender As Object, ByVal e As SerialDataReceivedEventArgs)
        Dim sp As SerialPort = CType(sender, SerialPort)
        Dim indata As String = sp.ReadExisting()
        'Console.WriteLine("Data Received:")
        'Console.Write(indata)
        'lblStatus.Text = indata
        'InBoundData = indata
    End Sub

    '** Button on form to open the com port if you need to select a different one
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        OpenComPort()
    End Sub
    '** speaks the Days difference for a date type give.
    '** This really should be more open ended but works for me 
    '** If you have a sub that just returns DAYS you could use it to adjust the comments to things like
    '** WOW its almost Christmas if days to are less than 7 or whatever
    '** Obviously these are hard coded and need to be updated to dynamically change... someday
    Private Sub SayDateDiff(ByVal SpecialDate As String)
        Dim MyDays As String
        MyDays = ""
        If SpecialDate = "Christmas" Then
            MyDays = DateDiff("d", Now(), "12/25/2015")
        ElseIf SpecialDate = "Halloween" Then
            MyDays = DateDiff("d", Now(), "10/31/2015")
        End If
        If MyDays <> "" Then
            SayIt(", it appears to be " & MyDays & " days until " & SpecialDate & ". ")
        End If
    End Sub

    Private Function RandomInterjection(ByVal InterjectionType As String)
        '** Just trying to add a bit more realism to the code
        '** You can call this to get a semi random statement back to say
        '** More types can be added as needed.
        '** Prefix is for normal responses before saying something
        '** Positive is for a good thing to say before
        '** Negative is for bad or unhappy things to say
        '** Wait is for when you have to go get more information to say online or similar.
        Dim r As Random = New Random
        Dim MyInterjections As String

        If InterjectionType = "PREFIX" Then
            MyInterjections = "Well,Ok,Ahh,So,Good"

        ElseIf InterjectionType = "POSITIVE" Then
            MyInterjections = "Good,Ok,That works. ,Cool beans. ,Good Deal. "

        ElseIf InterjectionType = "WAIT" Then
            MyInterjections = "Just a second. ,Lets see. ,Hang on. ,Let me see. ,This may take a second. ,Let me look 

that up. "

        ElseIf InterjectionType = "NEGATIVE" Then
            MyInterjections = "Sorry. ,I can't do that,No can do., Bummer."
        Else
            MyInterjections = "That was a bad interjection of " & InterjectionType & ". You  really should fix that 

code."
        End If

        '** Split out the selected string into an array and get a 'random' return from it
        Dim MyInterjectionA As Array
        MyInterjectionA = Split(MyInterjections, ",")

        RandomInterjection = MyInterjectionA(CInt(Math.Ceiling(Rnd() * UBound(MyInterjectionA))))

    End Function

End Class

 

Arduino Source
http://www.Protowrxs.com/robots/headbots/HeadBotBaseCode.ino 

// HeadBotBaseCode - From Box Head / DRHead Type of Animated Bot
// Stephen W Nolen / Protowrxs 2015
// v1.00 - Public 10/27/2015

//** Original code from Box Head
//** serial commands are in the main loop case - add or remove as needed

//** This ASSumes a few things - you are using RGB LEDs for eyes and you have at least ONE servo to rotate the neck
//** You will have to adjust and/or flip around the Left/Right and Up/Down limits on the servos to match your  needs



// Pin Use Defaults
// 0  RX from VB.net
// 1  TX to VB.net
// 2  
// 3  
// 4  Neck Rotate
// 5  Neck Up/Down
// 6  Jaw Servo
// 7  R Left Eye
// 8  G Left Eye
// 9  B Left Eye
// 10 R Right Eye
// 11 G Right Eye
// 12 B Right Eye
// 13
// A0
// A1 B Mouth       //** You should change this up if you are not using it or however the heck you want to configure things
// A2 G Mouth
// A3 R Mouth
// A4

// ** Includes area
#include <Servo.h>

Servo NeckRotate;
Servo NeckUpDown;
Servo Jaw;

long substeptimer;
int  substeps = 12;                      // this is how many increments we are going to move a servo for each walk step or "frame"

int MyTilt;
int MyRotate;

byte Blue = 0;                        // Just values to use for changing eye color LEDs
byte Red = 1;
byte Green = 2;
byte eyeColor = Red;                 // Start out normal with blue eyes
byte mouthColor = Green;              // start out with green mouth to test
byte currentMouth;   // default to this

byte currentLeftEye;
byte currentRightEye;

//** Adjust the head center/positions as needed for your configuration
byte HeadCenterLimit= 90;
byte HeadLeftLimit = HeadCenterLimit - 30;
byte HeadRightLimit=  HeadCenterLimit + 30;

//** Adjust the jaw center/positions as needed for your configuration
byte JawOpenLimit = 110;
byte JawClosedLimit = 59;
byte JawCurrentValue = JawClosedLimit;
byte JawHalfOpen = 85;

long TalkingTimer;
byte isTalking = 0;
long DelayToTalk = 200;             //** The delay from the command until the time sound may be heard from computer due ot the delay of eSpeak
long DelayToTalkTimer;              //** used with delaytotalk to wait to move jaw

//** For tilt options - adjust as needed
byte HeadMiddleLimit = 90;
byte HeadUpLimit = HeadMiddleLimit - 30;
byte HeadDownLimit= HeadMiddleLimit + 30;

float CurrentRotate;                  // Current neck rotate position - used as we do step movement to desired positions
float CurrentTilt;                    // Current tilt position for tracking
float NeckRotateInc;
float NeckTiltInc;

byte CurrentLook;                    // Current looking position for the head
byte LookingForward=0;               // general position tracking variables to easily know where looking or where to look
byte LookingDown  = 1;
byte LookingUp    = 2;
byte LookingLeft  = 3;
byte LookingRight = 4;
byte LookingMiddle= 5;

byte LookingCustom= 9;

int headrequest;

int LoopDelay = 50;                  // 

boolean MouthOpen = false;

boolean isawake;                // Used to blink eyes or not, etc

long motionTimer;                 //Used to determine when to make minor movements
int nextMotion;                   //Next time random motion will occur

long BoredTimer;
byte data = 0;
byte facedata;

// give eye pins a name so we can move things around if needed
int LeftR = 9;
int LeftG = 8;
int LeftB = 7;

int RightR = 12;
int RightG = 11;
int RightB = 10;

int eyesOpen = 1;
long blinkTimer;
long nextBlink;

//** This is the option to use a RGB led for the mouth instead of a jaw servo - not fully functional though
int MouthR = 13;
int MouthG = A0;
int MouthB = A1;

long generalTimer;
long nextMoveTime;


void setup()
{
  randomSeed(analogRead(0));

   // Default the Current values to avoid ackward start ups
  CurrentTilt = HeadMiddleLimit;
  CurrentRotate= HeadCenterLimit;

  NeckRotate.attach(4);     //** hook up the neck
  NeckRotate.write(CurrentRotate);
  
  Jaw.attach(6) ;           //** hook up the jaw - if this is ever used in EvilAnna
  Jaw.write(JawCurrentValue);

  NeckUpDown.attach(5);
  NeckUpDown.write(CurrentTilt);
  
  changeEyeColor();         //** initial condiguration

  //** setup all the pin modes as needed
  pinMode(MouthR, OUTPUT);
  pinMode(MouthG, OUTPUT);
  pinMode(MouthB, OUTPUT);

  currentMouth = MouthR;    //** Just using RED mouth for now but you could change this
  
  pinMode(LeftR, OUTPUT);     
  pinMode(LeftG, OUTPUT);     
  pinMode(LeftB, OUTPUT);     

  pinMode(RightR, OUTPUT);
  pinMode(RightG, OUTPUT);
  pinMode(RightB, OUTPUT);
  
  //** Write out the initial settings as needed
  digitalWrite(LeftR, HIGH);
  digitalWrite(LeftB, HIGH);
  digitalWrite(LeftG, HIGH);

  digitalWrite(RightR,HIGH);  
  digitalWrite(RightG,HIGH);  
  digitalWrite(RightB,HIGH);  
  
  digitalWrite(MouthR, HIGH);
  digitalWrite(MouthG, HIGH);
  digitalWrite(MouthB, HIGH);

  
  //** Init the VB Voice / Control port on hardware  
  Serial.begin(9600); // Open serial monitor at 115200 baud to see ping results.

  LookUp();
  
  BoredTimer = millis();

  //** Coolest to default to facetracking I think
  CurrentLook = LookingForward;
  headrequest = LookingForward;

  motionTimer = millis();     //** Start up motion random timer
  nextMotion = random(200,1000); //** when the next random movement will be
}

void loop()
{

  //** If we are in talking mode then we call the Talking() sub to move the jaw
  if ((isTalking == 1) && (getET(DelayToTalkTimer) > DelayToTalk))
  {
    Talking2();
  }
  
  if (getET(blinkTimer) > nextBlink)
  {
    if (isawake) 
    {
     BlinkEyes();
     blinkTimer = millis();
    }
    else
     {
     CloseEyes();
     }
  }

  //** Generate a little random head movement when it is awake to keep things interesting
  if (isawake)
  {
    if (getET(motionTimer) > nextMotion)  
    {
      randomHeadMove();
    }
  }
  
  headrequest = CurrentLook;

  //** If we have any inbound serial commands we need to process them
  if (Serial.available() > 0) 
  {
    data = Serial.read();	 // read the incoming byte:
    switch(data)
    {
        case 'r' : eyeColor = Red; changeEyeColor(); break;   //** Simple eye color changes if you are using RGB LEDs
        case 'b' : eyeColor = Blue; changeEyeColor();break;
        case 'g' : eyeColor = Green; changeEyeColor();break;
      	case 'U' : headrequest = LookingUp;  break;           //** Updated headrequest var to move th ehead around
        case 'T' : isTalking = 1; DelayToTalkTimer = millis();break;    //** This starts the random jaw animation on the servo on pin 5 if you are using it
        case 't' : isTalking = 0; CloseJaw(); break;                    //** Shuts down the talking code
        case 'G' : isawake = false; break;                  //** Says goodbye to the bot and turned off isawake
        case 'L' : headrequest = LookingLeft; break;        //** Just normal movements for the Pan and/or Tilt servos
        case 'R' : headrequest = LookingRight ; break;
        case 'D' : headrequest = LookingDown ;  break;
        case 'F' : headrequest = LookingForward; isawake = true;break;
        case 'M' : headrequest = LookingMiddle; break;
        case 'H' : WiggleHead(); break;                     //** This gives that acknowledgement that he/she/it heard something
        case '1' : mouthColor = Red; changeMouthColor(); break;            //** Commands to change the MOUTH RGB LED to different colors
        case '2' : mouthColor = Green; changeMouthColor(); break;
        case '3' : mouthColor = Blue; changeMouthColor(); break;
        case 'J' : OpenJaw(); break;                        //** open / close commands 
        case 'j' : CloseJaw(); break;
        case '?': ;break;
        default  : break;
    }

    if (data != 'S')
    {
      Serial.print(headrequest);
    }
  }

  
// ** Depending on what we have set the driverequest var to above we execute it here
// ** This could/should be in a sub to clean up the main loop but easier to debug right here

  switch (headrequest){
    case 0: 
      substeptimer = millis();
      LookForward();   	  
      break;
    case 1:
      substeptimer = millis();
      LookDown();
      break;
    case 2: 
      substeptimer = millis();
      LookUp();  
      break;
    case 3:
      substeptimer = millis();
      LookLeft();  
      break;
    case 4:
      substeptimer = millis();
      LookRight();
      break;
    case 5: 
      substeptimer = millis();
      LookMiddle();
    case 6: 
      substeptimer = millis();
      break;
    case 7:
      break;
    case 8:
      break;
    case 9:
      LookCustom();
      break;
      
  }  // End Current Step

  delay(LoopDelay);
}


void LookForward()
{
  TiltNeck(HeadMiddleLimit);
  RotateNeck(HeadCenterLimit);
  CurrentLook = LookingForward;
}
  

void LookUp()
{
  TiltNeck(HeadUpLimit);
  CurrentLook = LookingUp;

}

void LookDown()
{
  TiltNeck(HeadDownLimit);
  CurrentLook = LookingDown;
}

void LookCenter()
{
  NeckUpDown.write(90);
  CurrentTilt = HeadMiddleLimit;
  }


void LookLeft()
{
   RotateNeck(HeadLeftLimit);
   CurrentLook = LookingLeft;
}

void LookRight()
{
   RotateNeck(HeadRightLimit);
   CurrentLook = LookingRight;
}

void LookMiddle()
{
  TiltNeck(HeadMiddleLimit);
  CurrentLook = LookingMiddle;
}


void LookUpCenter()
{
  LookCenter();
  LookUp();
}

void LookDownCenter()
{
  LookDown();
  LookCenter();
}

void LookCustom()
{
  RotateNeck(CurrentRotate);
  TiltNeck(CurrentTilt);
  CurrentLook = LookingCustom;  
}


// ** returns the ET in millis for timer variable passed
long getET(long mytimer){
  long result;
  result = (millis() - mytimer);
  return result;
}

//** This moves to the position by the substeps provided
void RotateNeck(byte MoveToPosition){
  if (getET(substeptimer) < LoopDelay){
     NeckRotateInc = (MoveToPosition - CurrentRotate) / (substeps);
  }

  CurrentRotate = CurrentRotate + NeckRotateInc;

  NeckRotate.write(CurrentRotate);
}

//** This moves to the position by the substeps provided
void TiltNeck(byte MoveToPosition){
  if (getET(substeptimer) < LoopDelay){
     NeckTiltInc = (MoveToPosition - CurrentTilt) / (substeps);
  }

  CurrentTilt = CurrentTilt + NeckTiltInc;

  NeckUpDown.write(CurrentTilt);
}


// Directly position the rotation and update the current values
void RotateNeckPosition(byte MoveToPosition)
{
  //** Keep us in the master bounds just in case
  //** This is more likely to occur from Face Tracking
  MoveToPosition = constrain(MoveToPosition, HeadLeftLimit, HeadRightLimit);
  NeckRotate.write(MoveToPosition);
  CurrentRotate = MoveToPosition;
}

void TiltNeckPosition(byte MoveToPosition)
{
  MoveToPosition = constrain(MoveToPosition, HeadUpLimit, HeadDownLimit);
  NeckUpDown.write(MoveToPosition);
  CurrentTilt = MoveToPosition;
}

//** This just gives a nod when talking - Best to use this if you have tilt options!!!
void WiggleHeadOLD()
{
  NeckUpDown.write(CurrentTilt + 3);
  delay(100);
  NeckUpDown.write(CurrentTilt);
}

//** This just gives a nod when talking
void WiggleHead()
{
  NeckRotate.write(CurrentRotate + 3);
  delay(100);
  NeckRotate.write(CurrentRotate);
}


void BlinkEyes()
{
  
  digitalWrite(currentLeftEye,HIGH);
  digitalWrite(currentRightEye,HIGH);
  
  delay(random(100,300));               // wait for a second
  
  digitalWrite(currentLeftEye, LOW);   // turn the LED on (HIGH is the voltage level)
  digitalWrite(currentRightEye, LOW);   // turn the LED on (HIGH is the voltage level)
  
  nextBlink = random(2000,5000);  //** reset timer to next blink here
  blinkTimer = millis();
  
}

void CloseEyes()
{

  digitalWrite(LeftB,HIGH);
  digitalWrite(RightB,HIGH);
  digitalWrite(LeftR,HIGH);
  digitalWrite(RightR,HIGH);
  digitalWrite(LeftG,HIGH);
  digitalWrite(RightG,HIGH);
  
}

void OpenJaw()
{
  Jaw.write(JawOpenLimit);
  JawCurrentValue = JawOpenLimit;
  digitalWrite(currentMouth,LOW);
}

void CloseJaw()
{
  Jaw.write(JawClosedLimit);
  JawCurrentValue = JawClosedLimit;
  digitalWrite(currentMouth,HIGH);
}

void HalfJaw()
{
  Jaw.write(JawHalfOpen);
  JawCurrentValue = JawHalfOpen;
  digitalWrite(currentMouth,LOW);
}

void Talking()
{
  long TalkingDelay = random(50,300);
  if (getET(TalkingTimer) > TalkingDelay)
  {
    if (JawCurrentValue == JawOpenLimit)
    {
      HalfJaw();
      TalkingTimer = millis();
    }
    else
    {
      OpenJaw();
      TalkingTimer = millis();
    }
  }
}


void Talking2()
{
  long TalkingDelay = random(50,100);
  if (getET(TalkingTimer) > TalkingDelay)
  {
    int talkJaw = random(JawClosedLimit, JawOpenLimit);
    Jaw.write(talkJaw);
    TalkingTimer = millis();
    if (talkJaw > JawHalfOpen)
    {
      digitalWrite(currentMouth,LOW);
    }
    else
    {
      digitalWrite(currentMouth,HIGH);
    }
  }
}

void randomHeadMove()
{
  int randomOffset = random(-1,1);
  CurrentRotate = CurrentRotate + randomOffset  ;
  nextMotion = random(1000,3000);
  motionTimer = millis();
}

void changeEyeColor()
{
  digitalWrite(LeftB,HIGH);
  digitalWrite(RightB,HIGH);
  digitalWrite(LeftR,HIGH);
  digitalWrite(RightR,HIGH);
  digitalWrite(LeftG,HIGH);
  digitalWrite(RightG,HIGH);

  switch (eyeColor){
    case 0: // Blue
      currentLeftEye = LeftB;
      currentRightEye= RightB;
      break;
    case 1: // Red
      currentLeftEye = LeftR;
      currentRightEye= RightR;
      break;
    case 2: // Green
      currentLeftEye = LeftG;
      currentRightEye= RightG;
      break;
  }
  
}


void changeMouthColor()
{
  digitalWrite(MouthR,HIGH);
  digitalWrite(MouthB,HIGH);
  digitalWrite(MouthG,HIGH);

  switch (mouthColor){
    case 0: // Blue
      currentMouth = MouthB;
      break;
    case 1: // Red
      currentMouth = MouthR;
      break;
    case 2: // Green
      currentMouth = MouthG;
      break;
  }
}

 

Update 11/4/2015: Just a couple updates that can help with this that I've added to my core code.

If you are using eSpeak or other command line called items, add this to the properties to remote that annoying DOS box that pops up each time.

start.CreateNoWindow = True

That just hides the windows but still runs the command.

Also if you have issues with constant false recognizing instances there are a couple options I've used.

One is to use RobotName & " This is my command" for each statement. You do have to say the robots name and then then command but it's less likely to trigger on general conversation or TV sounds, etc.

The second option is to start a timer when the "Hello " & RobotName command runs and have the timeout turn off ListenFlag after a minute or whatever you set the time for. I'll dig out where I played with that but it's as easy as adding a timer to the form and controlling it.

Just some thoughts from when I added this to my old living room PC for purely controlling my home automation stuff.

Stephen

Comments

Submitted by Roxanna77 on Thu, 2015-10-29 06:08

Roxanna77's picture
I was going to ask you for some starting code for doing something like this! And such a great write up too. Many thanks!
Submitted by JeffRo on Thu, 2015-10-29 12:50

JeffRo's picture
Proto great work on the code. You might want to try using the VisemeID to control the mouth movements. Here is some sample code to help get you started. Hope to see more from you on this.

Option Explicit
Private V As SpeechLib.SpVoice
Private Sub Command1_Click() Dim ii As Integer
On Error GoTo EH
Text2.Text = "" V.Speak Text1.Text, SVSFlagsAsync
Do For ii = 0 To 20000 DoEvents Next ii Text2.Text = Text2.Text & V.Status.VisemeId & " "
Loop While V.Status.RunningState = SRSEIsSpeaking
EH: If Err.Number Then ShowErrMsg End Sub
Private Sub Form_Load()
Set V = New SpVoice Text1.Text = "say, see, sigh, so, sue." Text2.Text = ""
End Sub
Private Sub ShowErrMsg()
' Declare identifiers: Dim T As String
T = "Desc: " & Err.Description & vbNewLine T = T & "Err #: " & Err.Number MsgBox T, vbExclamation, "Run-Time Error" End
End Sub
Submitted by Ladvien on Fri, 2015-10-30 07:31

Ladvien's picture
Mr. Stephen! Nifty build, sir. I've wanted to build a talking skull for my desk for awhile now. I'm glad to know I'm not the only one. :) Although I've not coded in VB in 15 years, I still have a special place in my heart for VB, since it was my first real language. It's good to see "Dim" again.
Submitted by Roxanna77 on Fri, 2015-10-30 16:58

Roxanna77's picture
Like Ladvien, been long time since I did any VB. Thanks to the sources links I got it installed and running on my Win10 laptop, and in little time was able to have my PC carrying on conversations with me with the code supplied. Now I'm playing around with RSS feeds trying to parse out beyond the headlines... that is not easy, not sure I have the skills for that, but its fun trying. I'm going to try to code a Propeller for the microcontroller. Thanks again Protowrxs!
Protowrxs's picture
Author: 
Protowrxs
Last updated: 
4 Nov 2015 - 10:54