Caixa de casamento no RASPBERRY

Fala galera!
Hoje vou mostrar pra vocês o grande projeto no qual eu estava empenhado ao longo de todos esses meses.

Segue o vídeo abaixo, e caso quiserem saber como foi feito , clique no link mais!

O projeto era: Uma caixa de casamento para entregar os presentes dos padrinhos.

 

IMG_20160125_100638967 IMG_20160125_100618519
IMG_20160125_100520172 IMG_20160125_100436133_HDR

 

A caixa consiste em:IMG_20160125_100428627

  1. Motor de Passo + Driver Uln2003 (FilipeFlop.com)
  2. MOSFET Power Control (Sparkfun)
  3. Protoboard simples
  4. Cabo USB
  5. Uma LUZ que eu retirei de uma lanterna de 5V
  6. Powerbank , ou um carregador externo de celulares de 5v (2A).
  7. Caixinhas de som com alimentação USB
  8. WebCam com microfone embutido

 

Utilizei um software chamado JASPER para fazer o reconhecimento de VOZ, porém para português só existe via Google Speech, e também é somente acadêmico para LINUX ou qualquer outro SO, com exceção do android, que já tem ele nativamente.

Primeiro instale o JASPER e siga todas as instruções de instalação do site, depois:

Para obter a chave da API do Speech:
1. É necessário entrar no grupo do chromium com o seu email do gmail que você irá utilizar no projeto:
https://groups.google.com/a/chromium.org/forum/?fromgroups#!forum/chromium-dev
2. Crie um projeto no google console developer com o email que fez a inscrição no grupo:
https://console.developers.google.com/project
3. Selecione o seu projeto e vá em “APIs & Auth.” E ative o Speech API.
4. Em “APIs & Auth,” vá até “Credentials.” e crie uma chave pública para acesso à API.
5. adicione sua credencial no  profile.yml. coloque a chave na aba ‘keys’

6. Configure o ‘stt_engine’ em seu profile.yml para ‘google’

profile.yml:
        …
        timezone: US/Pacific
        stt_engine: google
        keys:
            GOOGLE_SPEECH: $YOUR_KEY_HERE

na pasta client/stty.py procure por ‘google’ e forçe a linguagem para pt-br no __init__ assim não teremos problemas
    def __init__(self, api_key=None, language=’pt-br’):

 

Com isso teremos nosso JASPER instalado corretamente.

Depois disso iremos configurar nosso motor de passo:
Nesse caso eu fiz uma trava com uma barra de ferro e colei com algodão e super cola (realmente funciona) e acima coloquei um gancho para travar a abertura da caixa

IMG_20160125_100659810

Assim quando o motor girar, o outro ferro ficará preso na curva e assim travando a caixa.

Configurando o motor:

Iremos colocar os pinos do motor na seguinte forma (para funcionar nos scripts que desenvolvi)

#GPIO21 (1) ,GPIO20 (2) ,GPIO16 (3) ,GPIO12 (4) e 5v e GROUND nos 2 pinos indicados

O raspberry não suportará que você alimente dele 5v o motor de passo e a luz, portanto fiz uma adaptação no cabo de entrada para sair 3 pontas de conexão, assim isolando o raspi do motor e da luz

IMG_20160125_101041697_HDR

Configurando a Webcam

Utilizaremos o software fswebcam

e podemos fazer um script para executar essa chamada da seguinte forma:

#!/bin/bash

DATE=$(date +"%Y-%m-%d_%H%M")

fswebcam -r 1280x720 --no-banner /home/pi/webcam/$DATE.jpg

dê a permissão 777 para ele e a webcam tirará uma foto toda vez que você chamar o ./webcam.sh

Espeak

Utilizaremos o espeak para sintetizador de voz da caixa, com a lingua portuguesa, não é 100% , mas se você jogar com as palavras de acordo com a pronuncia dele, fica legal, (muitas vezes digitei vosseis para ele falar vocês corretamente)

espeak -v pt-br+m3 -p 40 -s 130 "Raspi br.com.br"

Então fiz a modificação final no jasper.py , raiz do jasper, para que eu pudesse utilizar as funcionalidades dele.

 

#!/usr/bin/env python2
# -*- coding: utf-8-*-
import os
import sys
import shutil
import logging
import re

from unicodedata import normalize
import yaml
import argparse

from client import tts, stt, jasperpath, diagnose
from client.conversation import Conversation

import time
import RPi.GPIO as GPIO
GPIO.setwarnings(False)

# Add jasperpath.LIB_PATH to sys.path
sys.path.append(jasperpath.LIB_PATH)

parser = argparse.ArgumentParser(description='Jasper Voice Control Center')
parser.add_argument('--local', action='store_true',
                    help='Use text input instead of a real microphone')
parser.add_argument('--no-network-check', action='store_true',
                    help='Disable the network connection check')
parser.add_argument('--diagnose', action='store_true',
                    help='Run diagnose and exit')
parser.add_argument('--debug', action='store_true', help='Show debug messages')
args = parser.parse_args()

if args.local:
    from client.local_mic import Mic
else:
    from client.mic import Mic


class Jasper(object):
    def __init__(self):
        self._logger = logging.getLogger(__name__)

        # Create config dir if it does not exist yet
        if not os.path.exists(jasperpath.CONFIG_PATH):
            try:
                os.makedirs(jasperpath.CONFIG_PATH)
            except OSError:
                self._logger.error("Could not create config dir: '%s'",
                                   jasperpath.CONFIG_PATH, exc_info=True)
                raise

        # Check if config dir is writable
        if not os.access(jasperpath.CONFIG_PATH, os.W_OK):
            self._logger.critical("Config dir %s is not writable. Jasper " +
                                  "won't work correctly.",
                                  jasperpath.CONFIG_PATH)

        # FIXME: For backwards compatibility, move old config file to newly
        #        created config dir
        old_configfile = os.path.join(jasperpath.LIB_PATH, 'profile.yml')
        new_configfile = jasperpath.config('profile.yml')
        if os.path.exists(old_configfile):
            if os.path.exists(new_configfile):
                self._logger.warning("Deprecated profile file found: '%s'. " +
                                     "Please remove it.", old_configfile)
            else:
                self._logger.warning("Deprecated profile file found: '%s'. " +
                                     "Trying to copy it to new location '%s'.",
                                     old_configfile, new_configfile)
                try:
                    shutil.copy2(old_configfile, new_configfile)
                except shutil.Error:
                    self._logger.error("Unable to copy config file. " +
                                       "Please copy it manually.",
                                       exc_info=True)
                    raise

        # Read config
        self._logger.debug("Trying to read config file: '%s'", new_configfile)
        try:
            with open(new_configfile, "r") as f:
                self.config = yaml.safe_load(f)
        except OSError:
            self._logger.error("Can't open config file: '%s'", new_configfile)
            raise

        try:
            stt_engine_slug = self.config['stt_engine']
        except KeyError:
            stt_engine_slug = 'sphinx'
            logger.warning("stt_engine not specified in profile, defaulting " +
                           "to '%s'", stt_engine_slug)
        stt_engine_class = stt.get_engine_by_slug(stt_engine_slug)

        try:
            slug = self.config['stt_passive_engine']
            stt_passive_engine_class = stt.get_engine_by_slug(slug)
        except KeyError:
            stt_passive_engine_class = stt_engine_class

        try:
            tts_engine_slug = self.config['tts_engine']
        except KeyError:
            tts_engine_slug = tts.get_default_engine_slug()
            logger.warning("tts_engine not specified in profile, defaulting " +
                           "to '%s'", tts_engine_slug)
        tts_engine_class = tts.get_engine_by_slug(tts_engine_slug)

        # Initialize Mic
        self.mic = Mic(tts_engine_class.get_instance(),
                       stt_passive_engine_class.get_passive_instance(),
                       stt_engine_class.get_active_instance())

    def remover_acentos(self , txt):
        return normalize('NFKD', txt).encode('ASCII','ignore').decode('ASCII')


    def destravar(self,steps):
        GPIO.setmode(GPIO.BOARD)

        #Pinos de conexao ao motor
        #Pinos 40, 38, 36, 32
        #GPIO21,GPIO20,GPIO16,GPIO12
        StepPins = [7, 8, 10, 11]

        #Define os pinos como saida
        for pin in StepPins:
            GPIO.setup(pin, GPIO.OUT)
            GPIO.output(pin, False)

        #Sequencia de ativacao
        Seq = [[1, 0, 0, 0],
            [1, 1, 0, 0],
            [0, 1, 0, 0],
            [0, 1, 1, 0],
            [0, 0, 1, 0],
            [0, 0, 1, 1],
            [0, 0, 0, 1],
            [1, 0, 0, 1]]

        StepCount = len(Seq)-1

        #Configura sentido de giro
        StepDir = -2  # 1 ou 2 para sentido horario
            # -1 ou-2 para sentido anti-horario

        #Tempo de espera
        WaitTime = 0.000000001
        StepDir =-2
        delay = int(10) / 1000.0;
        StepCounter = 0;
        for k in range(0,steps):
            for pin in range(0, 4):
                xpin = StepPins[pin]
                print StepCounter
                print pin
                if Seq[StepCounter][pin] != 0:
                    print " Step %i Enable %i" % (StepCounter, xpin)
                    GPIO.output(xpin, True)
                else:
                    GPIO.output(xpin, False)

            StepCounter += StepDir

            #Ao final da sequencia, reinicia o processo
            if (StepCounter >= StepCount):
                StepCounter = 0
            if (StepCounter < 0):
                StepCounter = StepCount
            time.sleep(delay);






    def run(self):

        self.mic.say("Olá, eu sou a caixa de casamento da Juliana e do Marcus");
        self.mic.say("Sou especial, e somente algumas pessoas poderão ter acesso ao meu conteudo");
        encontrou = False;
        thiago = False;
        while encontrou == False:
            self.mic.say("Depois do bipe, Diga seu nome");
            nome ='';
            input = self.mic.activeListenToAllOptions(MUSIC=True);
            print input
            for retorno in input:
                text = self.remover_acentos(retorno)
                if text:
                    if (re.search(r'\bRODRIGO\b', text, re.IGNORECASE)):
                        encontrou = True;
                        nome = "Rodrigo, seu gato!!!";
                        frase = "Oi {0} ".format(nome);
                    elif (re.search(r'\bPAULA\b', text, re.IGNORECASE)):
                        encontrou = True;
                        nome = "Paula.......... ou melhor........ oi Tata.";
                        frase = "Oi {0} ".format(nome);
                    elif ((re.search(r'\bTati\b', text, re.IGNORECASE)) or (re.search(r'\bTatiane\b', text, re.IGNORECASE)) or (re.search(r'\bMarcio\b', text, re.IGNORECASE))):
                        encontrou = True;
                        nome = "Marcio e tati";
                        frase = "Oi {0} ".format(nome);


                    elif ((re.search(r'\bAlex\b', text, re.IGNORECASE)) or (re.search(r'\bAndressa\b', text, re.IGNORECASE)) ):
                        encontrou = True;
                        nome = "Andrêssa .... Oi.... alex musculo puro";
                        frase = "Oi {0} ".format(nome);

                    elif ((re.search(r'\bVanessa\b', text, re.IGNORECASE)) or (re.search(r'\bEduardo\b', text, re.IGNORECASE)) or (re.search(r'\bEdu\b', text, re.IGNORECASE)) or (re.search(r'\bMiguinha\b', text, re.IGNORECASE)) ):
                        encontrou = True;
                        nome = " Miguinha .... Oi Du ... e oi Lorenzo!.... E finalmente a miguinha arrumou um miguinho... e vai desencalhar!";
                        frase = "Oi {0} ".format(nome);

                    elif ((re.search(r'\bAndreia\b', text, re.IGNORECASE)) or (re.search(r'\bAndrea\b', text, re.IGNORECASE))  ):
                        encontrou = True;
                        nome = " Andreia ... Vamos abrir umas forminhas para o casamento? ... kkkkk brincadeira!";
                        frase = "Oi {0} ".format(nome);


                    elif ((re.search(r'\bGabriel\b', text, re.IGNORECASE)) or (re.search(r'\bGabi\b', text, re.IGNORECASE))):
                        encontrou = True;
                        nome = "Gabriel, enfim conseguimos uma hora para nos encontrarmos!";
                        frase = "Oi {0} ".format(nome);
                    elif ((re.search(r'\bFilipe\b', text, re.IGNORECASE)) or (re.search(r'\bFi\b', text, re.IGNORECASE))):
                        encontrou = True;
                        nome = "Filipe";
                        frase = "Oi {0} ".format(nome);
                    elif ((re.search(r'\bTiago\b', text, re.IGNORECASE)) or (re.search(r'\bMICHELE\b', text, re.IGNORECASE))):
                        encontrou = True;
                        thiago = True;
                        nome = "Tiago, seu cabasso!, e olá michele!";
                        frase = "Oi {0} ".format(nome);

                    elif ((re.search(r'\bBianca\b', text, re.IGNORECASE)) or (re.search(r'\bBia\b', text, re.IGNORECASE)) or (re.search(r'\bAlisson\b', text, re.IGNORECASE))):
                        encontrou = True;
                        nome = "Bianta, oi alisson , seu gostoso, que vontade de te morder, se eu tivesse dentes , snif snif!";
                        frase = "Oi {0} ".format(nome);
                    elif ((re.search(r'\bRenata\b', text, re.IGNORECASE)) or (re.search(r'\bRe\b', text, re.IGNORECASE)) ):
                        encontrou = True;
                        nome = "Renata!";
                        frase = "Oi {0} ".format(nome);

                    elif ((re.search(r'\bCris\b', text, re.IGNORECASE)) or (re.search(r'\bCristina\b', text, re.IGNORECASE)) or (re.search(r'\bLeo\b', text, re.IGNORECASE)) or (re.search(r'\bLeandro\b', text, re.IGNORECASE))):
                        encontrou = True;
                        nome = "Leo e Cris, gostaria de agradecer, primeiramente, por serem o cupido dessa relassao. Nada disso iria acontecer sem vosseis";
                        frase = "Oi {0} ".format(nome);

                if encontrou:
                    self.mic.say(frase);
                    if thiago == True:
                        self.mic.say("Antes de comessarmos, por  favor, tire o sapatenis, tiago");
                    self.mic.say("Como sabem, eles irão se casar, e será no dia 3 de Dezembro de Dois mil e dezesseis.");
                    self.mic.say("E para isso, eles precisam de pessoas importantes e especiais ao lado deles. Para que Fassam parte desse momento, de um jeito, único e especial");

                    Abrir = False;
                    if thiago == True:
                        self.mic.say("Para abrir a caixa, depois do bipe, complete a frase");
                        self.mic.say("Pai.... nosso ... que ....");
                        self.mic.say("kkkkkkkk, zoeira, eu sou uma caixa muito zoeira!");
                    while Abrir == False:
                        self.mic.say("Para abrir a caixa, depois  do bipe, diga ABRIR");

                        input = self.mic.activeListenToAllOptions(MUSIC=True);
                        for retorno in input:
                            text = self.remover_acentos(retorno)
                            print text
                            if text:
                                if (re.search(r'\bABRIR\b', text, re.IGNORECASE)):
                                    Abrir = True;
                    self.mic.say("Enquanto destravo a caixa, aguarde a luz vermelha da camera acender, para uma foto!");
                    os.system( 'sudo /home/pi/python_projects/webcam.sh&' );
                    self.destravar(700);
                    GPIO.setup(26,GPIO.OUT);
                    GPIO.output(26,1);
                    self.mic.say("A caixa foi destravada, pode abrir");
                    os.system( 'omxplayer /home/pi/python_projects/jasper/static/Thousand.mp3' );
                    sys.exit(1);


if __name__ == "__main__":

    print("*******************************************************")
    print("*             JASPER - THE TALKING COMPUTER           *")
    print("* (c) 2015 Shubhro Saha, Charlie Marsh & Jan Holthuis *")
    print("*******************************************************")

    logging.basicConfig()
    logger = logging.getLogger()
    logger.getChild("client.stt").setLevel(logging.INFO)

    if args.debug:
        logger.setLevel(logging.DEBUG)

    if not args.no_network_check and not diagnose.check_network_connection():
        logger.warning("Network not connected. This may prevent Jasper from " +
                       "running properly.")

    if args.diagnose:
        failed_checks = diagnose.run()
        sys.exit(0 if not failed_checks else 1)

    try:
        app = Jasper()
    except Exception:
        logger.error("Error occured!", exc_info=True)
        sys.exit(1)

    app.run()

Podemos colocar nosso script para funcionar assim que o raspberry for iniciado. Para isso vá em

etc/xdg/lxsession/LXDE, abra o arquivo autostart e coloque:

cd /caminho/da/sua/pasta/jasper/
sudo python jasper.py –debug

Aos que tiverem interesse, terei maior prazer em disponibilizar os fontes!

Em breve volto a postar as coisas novamente!

Valeuuuu