Thursday, January 5, 2017

Giving a voice to someone who's lost the ability to speak.

As they say, necessity can be the mother of invention.  

    In December of 2016 I lost my best friend of over 30 years.   He had suffered a major stroke and was in a coma for just over a week.   He came out of the coma, but could not speak, and could only move his hands a bit and feet.   He was in there, he could communicate by squeezing his hand, but that was all.

   I immediately dreamed up a way of giving him a voice back.   This project is the result.

   Unfortunately,  my friend had a second stroke and didn't survive.   I decided to go ahead with the project though,  I'm hopeful that it can help someone out there somewhere.   I call it,  The CW Voice Box.

   Morse code is one of the oldest ways of sending letters with a simple on off signal.   Short patterns of long and short tones.  An ideal way for someone who can only squeeze, bite, or blink to be able to spell out words.    This project is exactly that.  You key in Morse code, it speaks the letters.   A voice for the voiceless.

   There are other devices out there to accomplish this, it's not a new idea.   However,  those devices are expensive!   With the technology we have today,  you can build my voice box for around 45 bucks.    Maybe a little more if you want a fancy case.

The parts list:

     Computer:    Raspberry Pi zero.     I recommend the starter pack over at Adafruit: $24.95
Adafruit Raspi budget pack.

     USB sound card:     There's many available on Amazon,  here's one that works:   $5.99
USB sound card

     8 Gig micro SD card.    $7

     5 volt audio amp:   There's lots of these to choose from,  one example below:  $7
Audio amp

     A speaker of some type.   I'll leave that up to you.

     You'll also need some bits of wire, some kind of a case, and an input device.    Regarding input devices....    What you need will depend entirely upon the capabilities of the person you are trying to help.    There are commercial squeeze bulb switches,   bite switches,   and other devices available.   I'll leave the input method up to you.    The only requirement is that the person needs to be able to input long and short signals in a pattern.

     Putting it all together:

     I've already done the hard work on the software.   I have built a Raspian image for your Pi zero that will boot directly into the morse decoding speech software.   You can download the image from the link below.

Custom Raspian image zip file.

(Many thanks to bitchen.com for offering to host the file.)

    Write this image to the micro SD card and put it in the pi.

     The starter pack will come with a 2Amp power supply,  plug that into the pi.
      Using the USB adapter, you can plug in the usb audio dongle to the second micro usb port on the pi.
      Your input device will need to connect to GPIO pin 7 on the pi, and also to ground.

      The audio amp will need 5 volts.   You can tap that from pin 2 on the pi.  It also needs a ground connection.

      Audio from the USB dongle goes to the input of the amp, and obviously the speaker will connect to it's output.

      When you plug in the power supply,  the pi should boot and within about 20 seconds it will speak the word  "Ready".    you're good to go.   Simply start keying in Morse and it will speak each letter, number, and some punctuation.

     It will reliably decode Morse from around 5 words per minute speed, up to about 10 words per minute speed.   To get an idea of the speed,  watch the demo towards the end of my video about the project,  linked below.


Full video.


    The software is built upon a great educational python program on the raspberry pi site.   I modified the software to make it compatibly with python3,  re-ordered it's lookup table for speed, and integrated espeak speech synthesis.    The raspian image was further modified to fix espeak errors with alsa, and set to boot to command line and run the decoder on boot.

    The original morse code decoder project on the raspberry site is linked below.

Morse decode I built upon.

My modified source code follows:

----------------------------------------------------

#!/usr/bin/python3
# modified code based on a tutorial project on the raspberry pi organizations web site.
# original project can be found here:
# https://www.raspberrypi.org/learning/morse-code-virtual-radio/worksheet/
import pygame
import time
from RPi import GPIO
import _thread
from array import array
from pygame.locals import *
from morse_lookup import *
from espeak import espeak

pygame.mixer.pre_init(44100, -16, 1, 1024)
pygame.init()

class ToneSound(pygame.mixer.Sound):
    def __init__(self, frequency, volume):
        self.frequency = frequency
        pygame.mixer.Sound.__init__(self, self.build_samples())
        self.set_volume(volume)

    def build_samples(self):
        period = int(round(pygame.mixer.get_init()[0] / self.frequency))
        samples = array("h", [0] * period)
        amplitude = 2 ** (abs(pygame.mixer.get_init()[1]) - 1) - 1
        for time in range(period):
            if time < period / 2:
                samples[time] = amplitude
            else:
                samples[time] = -amplitude
        return samples

def wait_for_keydown(pin):
    while GPIO.input(pin):
        time.sleep(0.01)

def wait_for_keyup(pin):
    while not GPIO.input(pin):
        time.sleep(0.01)

def decoder_thread():
    global key_up_time
    global buffer
    new_word = False
    while True:
        time.sleep(.01)
        key_up_length = time.time() - key_up_time
        if len(buffer) > 0 and key_up_length >= 1.5:
            new_word = True
            bit_string = "".join(buffer)
            try_decode(bit_string)
            del buffer[:]
        elif new_word and key_up_length >= 4.5:
            new_word = False
            sys.stdout.write(" ")
            sys.stdout.flush()

tone_obj = ToneSound(frequency = 800, volume = .03)

pin = 7
GPIO.setmode(GPIO.BOARD)
GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)

DOT = "."
DASH = "-"

key_down_time = 0
key_down_length = 0
key_up_time = 0
buffer = []

_thread.start_new_thread(decoder_thread, ())

print("Ready")
espeak.synth("Ready")

while True:
    wait_for_keydown(pin)
    key_down_time = time.time() #record the time when the key went down
    tone_obj.play(-1) #the -1 means to loop the sound
    wait_for_keyup(pin)
    key_up_time = time.time() #record the time when the key was released
    key_down_length = key_up_time - key_down_time #get the length of time it was held down for
    tone_obj.stop()
    buffer.append(DASH if key_down_length > 0.3 else DOT)


------------------------------

And the morse_lookup.py source as well.

---------------------------------

#!/usr/bin/python
import sys
from espeak import espeak

morse_code_lookup = {
    ".":    "E",
    "-":    "T",
    ".-":    "A",
    "---":    "O",
    "..":    "I",
    "-.":    "N",
    "...":    "S",
    "....":    "H",
    ".-.":    "R",
    "-..":    "D",
    ".-..":    "L",
    "-.-.":    "C",
    "..-":    "U",
    "--":    "M",
    ".--":    "W",
    "..-.":    "F",
    "--.":    "G",
    "-.--":    "Y",
    ".--.":    "P",
    "-...":    "B",
    "...-":    "V",
    "-.-":    "K",
    ".---":    "J",
    "-..-":    "X",
    "--.-":    "Q",
    "--..":    "Ze",
    ".----":    "1",
    "..---":    "2",
    "...--":    "3",
    "....-":    "4",
    ".....":    "5",
    "-....":    "6",
    "--...":    "7",
    "---..":    "8",
    "----.":    "9",
    "-----":    "0",
    "..--..":    "question mark",
    ".-.-.-":    "period"
}

def try_decode(bit_string):
    if bit_string in morse_code_lookup.keys():
#        sys.stdout.write(morse_code_lookup[bit_string])
        espeak.synth(morse_code_lookup[bit_string])
#        sys.stdout.flush()

------------------------------------
 


    Please share,  I hope this project will get out there and find someone who can use it.    I would be absolutely thrilled to hear back from someone who was able to give a voice back to somebody who'd lost theirs.

    Thanks,

Kevin.

3 comments:

  1. This is amazing! Thank you so much for sharing. My grandma has Motor Neuron Disease and has lost the ability to speak. I'd like to make a Russian version for my science fair project. I'm am going to reference your work. Can you please clarify what date you made the CW?

    ReplyDelete
  2. I don't understand the question. What Date?
    Regarding the language, you'll find a flag for Russian in the espeak documentation. It should be easy to add that flag into the python code to give it an accent.

    ReplyDelete
  3. i like this page
    I really like you post.
    I would like to share page collection with you!
    thanks you for share

    gclub casino
    gclub
    golden slot mobile
    gclub Casino online

    ReplyDelete