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.
- Motor de Passo + Driver Uln2003 (FilipeFlop.com)
- MOSFET Power Control (Sparkfun)
- Protoboard simples
- Cabo USB
- Uma LUZ que eu retirei de uma lanterna de 5V
- Powerbank , ou um carregador externo de celulares de 5v (2A).
- Caixinhas de som com alimentação USB
- 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
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
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