It’s been a while, but speech, light and sound are done!
So last time I wrote, I was complaining about wire.h and though I’d need to re-write it. Fortunately, that didn’t end up being the case. The root cause of me thinking I needed to re-write wire.h was that the longer I’d run the speech code for, the higher the chance of me getting a “FAULT” returned from the I2C code. The root cause was that I should have tied the A/R (Acknowledge) pin to an interrupt rather than try and poll it, since it is only pulsed on for a short period, and easy for my code to miss in the main loop. Should have done this right off the bat, but.. live and learn I guess.
All of the source code for the HERO 1 project is now available on BitBucket in case anyone is interested in following along. You can access the repository here:
https://bgriley01@bitbucket.org/bgriley01/the-hero-1-project.git
Having gotten speech completed, I moved on to light and sound – which are both controlled by the same board.
The sound/light was a bit easier than the speech since I had laid a lot of groundwork when I wrote the speech module. I had also already established Communication methods between Pi and Trinket.
A separate trinket now controls the sense board.
There are three primary inputs into the sense board (aside from voltage & ground)
- Enable pin
- Selector pin (set high for light, and low for sound)
- clock pin
Then there are eight output pins from the sense board that come from the sense board analog to digital converter and represent 8 bits of data.
The problems encountered:
- The clock pin requires a 1 MHz frequency, which I originally wanted to get from the Trinket via PWM. It seemed though that there is no direct link to the clock cycle of the Trinket, and the highest PWM frequency I could achieve from the Trinket/Arduino was about 895Hz – nowhere near what I wanted. I then redirected to the Pi and was able to get the clock frequency I needed via the wiringpi API.
- I wasn’t getting any readings from the light sensor initially, and as I traced it back, I discovered the problem was a faulty LDR. To test it, I ended up disassembling a bit of HERO’s head as it quite buried. I tested it, and to my surprise, it was working great – then I realized there was no voltage going to it. A bit of tracing through the wiring diagrams, and I realized that I needed to send +5V and ground up to HEROs head via some more connectors on the I/O board. Voilà! The light sensor started working.
After running some tests on the Arduino, I moved the code to the Trinket and finally soldered the connections on the I/O board. I now have working readings coming from both the light and sound sensor (though as per HERO’s original design, only one can work at a time… light or sound, not both).
Hi Brian!
I've been keenly following your project which has been super insightful. I don't have a Hero-1, but I'm interested in reviving the speech board and expanding it using the CMU dictionary. I managed to build the Hero-1 speech board based on the schematics in the manual, and with the help of your posts have it working, confirmed by a "ready" when I switches it on 🙂
I have the RPI and Arduino all wired up and ready to go, but I'm getting an error when compiling your files from GitHub:
c++ -c src/Apps/speechSynth.cpp -o obj/speechSynth.o -Isrc
error: unable to open output file 'obj/speechSynth.o': 'No such file or directory'
Is this an issue in the makefile, or am I missing something else?
Thank you! Sorry it took so long to respond – I really appreciate the comment and am actually sort of surprised to have someone trying to reproduce my results! It's such a niche project after all!
I believe the issue is that it's trying to write to the "obj" directory and it doesn't exist. I've modified the makefile so it will create the directory now. Please let me know if you have any other problems and I'll try and respond in less than 2 months 😉
Fantastic that you’re back on this! I solved it in a similar way in the meantime 🙂
Everything is up and running for me now.
Hey, just wondering if you have any thoughts on programming the speech to parse a text file, rather than typing in words? Would that be done using Python’s “open” function?
Thanks again, and keep up the good work!
Hey! I’d been so long I thought I lost you!
Yeah, since the app can currently parse apart words out of a typed sentence, taking an input stream from a file should be quick work!
You might be able to just pipe a file as input into your existing executable. Something like
cat file.txt | speechprogram
might just do the trickOtherwise, I’d probably just write it in C++ and use the library directly.
Good luck with your project!
Yeah exactly. I ended up writing a C++ script and implementing it directly into the speechSynth.cpp in Apps. It works really well. And the great thing is that it can take a seemingly unlimited length of text!
Though there’s a bug that I’ve been experiencing from the beginning—not sure if you experienced it too. It’s that it seems to output a phoneme or two before the actual word; sounds something like “ShhHello World”. I’m getting some visual cues for the bug as well which displays as “BBBBBEnter Text:”
Nothing pops out for me in the code but maybe you’ve come across this?
Hmmm, that’s a strange one. No, I haven’t seen that – are you sure it’s coming from the library?
Oh interesting. At first I had wondered if it was a bug caused by my use of an Uno instead of a trinket, but then I came across this in /src/speech.cpp:
int Speech::Status(unsigned char* data, int len)
{
unsigned char rxBuffer[5]; // receive buffer
if(!data || len == 0)
{
data = rxBuffer;
len = 5;
}
memset(data, 0, sizeof(unsigned char) * len);
if(!sendOpCode(SPEECH_OPCODE_STATUS))
{
#ifdef DEBUG
cout << "Status request failed\n";
#endif
cout <<"AAAA";
return SPEECH_STATUS_FAULT;
}
//usleep(1000); //sleep for 1 millisecond
read(data, len);
if(*data != SPEECH_OPCODE_STATUS)
{
#ifdef DEBUG
cout << "Unexpected Response OPCODE: " << hex << (int)*data << dec << " len: " << len << "\n";
#endif
Controller::Abort();
cout <<"BBBBB";
return SPEECH_STATUS_FAULT;
}
/*else
cout << hex << (int)*(data+1);*/
return *(data+1);
}
Not sure if this reply field will reformat the code into a mush, but looks like this is where the "BBBBBEnter text:" is coming from.
Whoops – sounds like I forgot to remove a couple debug comments at some point. It may be worth building it in DEBUG to see what data is actually coming across.
It sounds like there are some invalid bytes making their way into the I2C communication. This would account for the strange noise before you hear speech as well as why you’re falling into the code that would print the “AAAA”, “BBBBB” debug statements.
I noticed in your votrax-pi-i2c.c that “HELLO” is represented as 0x1B, 0x02, 0x23, 0x18, 0x23, 0x16, 0x37,0x3E, 0xFF
However when I output the bytes after typing he “HELLO” (without quotes) I get 0x1B, 0x32, 0x18, 0x26, 0x3E, 0xFF
Did you experience something similar?
I don’t believe there is a file “votrax-pi-i2c.c” in my project. In fact, the code base is C++ (.cpp) and Arduino (.ino) files, so I’m not entirely sure what you’re talking about.