ZZ no Python

Pra quem não conhece, existe um conjunto de mini-programas para shell muito legal chamado Funções ZZ, criado pelo Aurélio Jargas (@oreio).

[Atualizado!] – Veja as novas funcionalidades no fim

Não sei se alguém já fez, mas criei um wrapper para essas funções em python, para os que já tem o ícone do Python no desktop e não querem abrir um terminal :).

Disponível em http://dl.dropbox.com/u/6016495/zz.py. Funciona tanto em Python 2 como em Python 3.

Exemplos:

>>> import zz
>>> int(zz.calcula('19+23'))
42
>>> zz.senha()
'k23Civ'
>>> zz.ramones()
'Come back baby, come back'
>>> zz.dolar
09/05/2011 compra   venda   hora
Comercial   1,618   1,620   17:01   +0,18
Paralelo    1,700   1,820   20/2/2011   0,00
Turismo     1,560   1,730   16:16   +0,58

>>> print(zz.loteria('megasena'))
megasena:
   08 - 11 - 14 - 30 - 36 - 38 
   Concurso 1281 (07/05/2011)
   Acumulado em R$ 2.000.000,00 para 11/05/2011

>>> zz.cpf('11111111111')
'CPF válido'
>>> zz.converte('cf', 32)
'32 C = 89.60 F'

[Novo!]
Agora também funciona com Pipes, podendo encadear funções ZZ e usar STDIN!
Mais exemplos:

>>> '1+2+3+4' | zz.calcula
'10'
>>> print('a\nb\nc\nd\na\nb\nc' | zz.uniq)
a
b
c
d
>>> 'oi, beleza?, oi, e ai, oi io, oi' | zz.contapalavra('oi', pipe=True)
'4'

Note que, se quiser ter uma chamada de função junto com o pipe, tem que adicionar o argumento “pipe=True”, senão ele calcula primeiro a resposta e tenta fazer a operação ‘or’ entre as strings. Podia ser esse segundo o comportamento padrão, mas teria que usar sempre um pipe pra pegar o valor final, que não é minha intenção.

A ideia de usar o operador ‘or’ pra fazer ligação entre chamadas de funções eu peguei desse site: http://dev-tricks.net/pipe-infix-syntax-for-python

Se quiser usar, pode colocar diretamente na pasta de módulos do Python, como por exemplo (no Linux):
/usr/local/lib/pythonX.Y/dist-packages

Bônus:
E, pra quem quiser, apresento o modo mais estranho de calcular 2+2+2+2:

>>> int((zz.calcula('2+2')[:-1]+'+2' | zz.calcula(pipe=True))[:-1] + '+2' | zz.calcula)
8
Anúncios

Python e Qt

Esse post não se chama Python + Arduino (Parte 3) porque agora estou usando outro microcontrolador, um Cortex M3.
Aliás, a ideia aqui é mostrar o uso de PyQt, um binding para usar Qt com Python.

Após baixar e instalar, você pode começar a programar interfaces no método convencional ou usar o QtDesigner (ferramenta do Qt) para fazer isso.

Por exemplo, você pode fazer assim:

Abra o QtDesigner e crie um novo projeto. Pode ser Widget ou MainWindow, faz pouca diferença no arquivo gerado.

Coloque seus botões, labels, caixas, etc:

Junte os sinais que não precisam de código. Aqui eu coloquei a caixa e o slider para um atualizar o valor do outro e o checkbox para desativar ou ativar o frame contendo a caixa e o slider.

Agora, você vai salvar um arquivo no formato .ui, que é um XML que vai ser usado para gerar o nosso programa.

Dentro da pasta de instalação do PyQt, que fica dentro do diretório do Python, existe uma ferramenta chamada pyuic4, que faz a conversão. No Linux, você pode rodar o programa diretamente, mas no Windows é uma boa criar um arquivo .bat contendo o comando que vai ser usado para converter o arquivo XML em código Python.

@”C:\Python32\python” “C:\Python32\Lib\site-packages\PyQt4\uic\pyuic.py” controle.ui > form.py

Verifique a pasta de instalação e escolha o nome do arquivo que você salvou e salve isso num arquivo com extensão .bat.
Agora é só dar dois cliques que deve surgir um arquivo chamado form.py, que contem uma classe para modificar uma janela que você tenha criado.

Agora você tem que criar um outro arquivo Python para ser seu programa a ser executado e criar alguns objetos. Existem bons tutoriais de PyQt4 pela internet, então não vou ficar detalhando muito.

Basicamente, você tem que criar um QApplication, uma janela (QWidget ou QMainWindow) e passar essa janela para a função do arquivo form.py que vai criar os botões, etc.

Após isso, você tem que conectar os sinais e os slots dos seus objetos para criar as funcionalidades desejadas. Neste caso, a cada evento no slider ou na caixa, um sinal serial está sendo enviado para o microcontrolador.

Cada slot é um novo método que você deve criar ou então usar de um artifício que são as funções lambda do Python.
Imagem do programa sendo executado:

Abaixo um exemplo de código:
Qualquer dúvida, faça um comentário!


from PyQt4 import QtGui, QtCore
import sys, serial 
import scan, form

class Main():
    def __init__(self):
        self.app = QtGui.QApplication(sys.argv)
        self.janela = QtGui.QMainWindow()
        self.ui = form.Ui_Form()  #Referências para elementos da janela
        self.ui.setupUi(self.janela)
        self.cria_slots()
        self.encontra_portas()
        self.janela.show()

    def cria_slots(self):
        self.ui.bt_conectar.clicked.connect(self.slot_conexao)
        self.ui.box_valor.valueChanged.connect(self.envia_info)
        self.ui.ck_ativar.clicked.connect(self.set_on_off)

    def encontra_portas(self):
        for porta in scan.scan():
            self.ui.box_porta.addItem(porta[0])

    #Criar outros métodos aqui

if __name__ == '__main__':
    prog = Main()
    prog.app.exec_()

Python + Arduino (Parte 2)

Além de plotar gráficos, com o Python é possível criar interfaces para modificar parâmetros do microcontrolador, enviando dados pela porta serial.

Como já visto na Parte 1 deste assunto, é preciso instalar o PySerial além do Python.

Desta vez eu fiz em uns 30 minutos um programa para enviar ao Arduino um número de 0 a 255 (8-bit) que serve para mudar o valor da resistência de um potenciômetro digital que deveria estar ligado à um amplificador de som.

Estou sem o amplificador no momento, então, para visualizar as mudanças coloquei um led para acender com PWM dentro do programa do arduino.

/*
 * Exemplo de leitura serial com o Arduino
 * Colocar isso dentro de um loop do programa
 */

char palavra[10];
unsigned char valor;

if (Serial.available()) {
    delay(100);
    unsigned char n = 0;
    while (Serial.available() > 0) {
        palavra[n++] = (Serial.read());
        //Cuidado com escrita fora do array
    }
    palavra[n] = '\0';

    valor = atoi(palavra);

    /*Usar o 'valor' para fazer alguma coisa, 
      como acender um Led com PWM*/
}

Outro dia coloco vídeo do sistema funcionando.

Python + Arduino

Não, ainda não dá para programar em Python para o ATmega, mas dá para acessar a porta serial pelo Python.

Recentemente descobri a existência do PySerial, um módulo para fazer acesso às portas seriais pelo Python, que tem me ajudado bastante a processar dados adquiridos pelo meu microcontrolador.

A melhor parte é que você pode coletar dados e, com ferramentas como Numpy e Matplotlib fazer diversas transformações e plotar gráficos bem interessantes.

Por exemplo, tenho um display de LCD cuja intensidade de luz é controlada por PWM provido pelo Arduino. A intensidade é escolhida de acordo com um valor lido num divisor resistivo com um resistor de 4.7K e um foto-resistor (LDR) que varia de 0 a 20K.

Eu escrevi um pouco sobre LDR aqui.

Para fazer o PWM, a tensão é lida numa porta analógica e passa por uma função escolhida empiricamente para a intensidade de luz ficar adequada ao ambiente. Sabe aquela coisa de que você tá querendo dormir e tem sempre um led de computador, televisão, aparelho de DVD ou outros aceso? Neste caso, o display fica com um mínimo de luminosidade quando está escuro.

Abaixo um gráfico gerado pelo sensor, usando Python.

Tensão lida(Azul), PWM (Verde) X Horário do dia:

Coloquei no pastebin um pequeno script em Python para coletar dados e salvar num arquivo.

Modo de uso:
1) Primeiro modifique a porta serial para a que você usa. No Linux é “/dev/ttyUSB“, no Windows é “COM“. Escolha também a taxa de transmissão adequada. O meu Arduino fica variando de /dev/ttyUSB0 para /dev/ttyUSB1, por isso tem uma função que busca a porta aberta.

2) Chame o script passando o número de amostras (o microcontrolador deve mandar quebras de linhas entre as amostras) e o nome do arquivo a ser gerado. Exemplo:

$ python meu_script.py 1234 nome_do_arquivo.txt

Para interromper a amostragem, aperte Ctrl+C e os dados serão salvos no arquivo antes de terminar o programa.

Para número indeterminado de amostras, coloque 0. Vai ficar pegando dados até você apertar Ctrl+C.

Programa foi escrito para Python 3, mas a única modificação necessária para Python 2 é retirar a chamada de str() na função de amostragem, pois a aquisição de dados é feito em strings de bytes e não unicode.

Os dados são salvos no arquivo assim:

['123', '546', '789', ... ]

Para obtê-los novamente no Python, faça:

>>> minha_lista = eval(open('nome_do_arquivo.txt').read())

Se estiver usando valores inteiros, converta a lista:

>>> minha_lista = [int(i) for i in minha_lista]

Caracteres personalizados

Estava vendo um post do Hack a day que mostrava um relógio num display de texto com os caracteres personalizados.

Cada letra do display de texto, ao menos esses com controlador HD44780 ou similar, é uma pequena matriz de 8 linhas por 5 colunas, sendo que você apenas escolhe o carácter e o controlador preenche a matriz.

Para estilizar os caracteres, você precisa gravar novos na memória volátil do controlador do LCD, sendo que ela tem espaço apenas para 8 (0 a 7 da tabela ASCII, não podem ser impressos). Os outros não podem ser modificados.

A ideia aqui é juntar 3 colunas para formar um número grande. Para isso, é preciso criar os caracteres que vão ser usados para desenhar as partes do número, sendo que precisam ser bem genéricos para que caibam nos 8 espaços da memória.

No caso eu usei 5 caracteres. Os três acima e as versões invertidas dos dois últimos. E criei os números como abaixo:

Para criar cada um dos 5 caracteres estilizados, é preciso enviar ao LCD o formato de cada uma das 8 linhas com números de 0 a 31, onde cada bit acende um ponto da linha. Você pode usar notação binária (por exemplo 0b10101) ou colocar o número decimal correspondente, se achar mais fácil.

Com as bibliotecas do Arduino, pode ser feito algo como:

LiquidCrystal lcd(2, 3, 4, 8, 9, 10, 11);
byte meus_chars[][8] = {{31,31,31,31,31,31,31,31}, 
                        {31,31,0,0,0,0,0,0},   
                        {0,0,0,0,0,0,31,31},
                        {31,31,0,0,0,0,0,31},
                        {31,0,0,0,0,0,31,31}};

for (byte i=0; i<5; i++){
    lcd.createChar(i, meus_chars[i]);
}

//Exemplo de exibição do número 0
lcd.clear();
lcd << '\0' << '\1' << '\0';
lcd.setCursor(0,1);
lcd << '\0' << '\2' << '\0';

Falando nisso, baixe a biblioteca Streaming que faz overload do << para imprimir coisas no LCD ou na Serial.

Abaixo um vídeo dos números no display:
Meu display 16×2 ainda não chegou. Enquanto isso, continuo com esse 8×2.

Projeto com display LCD

Com o advento do Arduino, fazer sistemas caseiros de controle ficou bem mais fácil, pois a IDE desse microcontrolador traz diversas bibliotecas que precisam de pouca configuração para acessar outros hardwares.

No final de semana eu fiz um pequeno projeto onde a hora e temperatura eram apresentadas num display LCD de texto com espaço para 8 caracteres em cada uma das suas duas linhas.

Para medir a temperatura eu usei um termômetro digital da Dallas Semiconductor, o DS18B20, que tem precisão de 0.0625 grau e já vem calibrado de fábrica.

Esse termômetro é um hardware bastante interessante, pois usa um protocolo chamado 1-Wire que permite diversos aparelhos conectados num fio e pode ser alimentado de forma parasita (pelo próprio fio de comunicação). Inclusive eu testei com dois termômetros conectados no mesmo fio e ambos apresentavam sempre a mesma temperatura (com uma diferença de no máximo 0.1 grau).

Basicamente, eles funcionam com um endereçamento de 64 bits, fazendo com que não exista confusão na comunicação. Essa forma de utilização é conhecida como microlan.

Para ajustar o horário, a solução mais simples foi mandar um comando serial para o microcontrolador, já que ele está conectado à USB e não tinha botões para colocar.

Abaixo deixo um vídeo onde eu seguro o termômetro e a temperatura (que já estava alta pelo calor do verão) aumenta um pouco mais.

Esse relógio-termômetro é parte de um projeto bem maior que estou fazendo para uma matéria da faculdade. Em breve mais coisas vão aparecer aqui.

Gerador de nomes pronunciáveis


Antes que o ano acabe, vou escrever aqui sobre um pequeno projeto em Python que fiz à dois dias atrás. A ideia é gerar palavras aleatórias, mas ao mesmo tempo “pronunciáveis”. Agora conta também com um gerador de Lorem Ipsum.

Basicamente você passa um arquivo contendo listas de fonemas separados do modo que você quiser com a probabilidade que cada lista deve ter.

Uma das listas existentes é a de vogais com a probabilidade de cada uma. Sem essa lista não dá para fazer nada.

Com isso, você pode definir fonemas como “ph_” que significa “pha”, “phe”, “phi”, “pho”, “phu” ou qualquer coisa que tenha sido definido como vogal, como “y”.

Também dá para definir coisas como ” *ç_-ei ” que significa que o cedilha não pode estar no início da palavra e o “_” não pode ser subtituído por “e” ou “i”, evitando “çe” ou “çi”.

Por fim, você pode fazer listas com nome “end_ALGUMACOISA” que significa que os elementos dessa seção não podem iniciar palavras, como seria feito com ” * “. No entanto, você pode colocar uma probabilidade alta para esses elementos e eles podem aparecer com mais frequência no fim da palavra.

Coloquei o arquivo .py e uma lista de fonemas no meu Dropbox, que pode ser acessado clicando na imagem abaixo (licença BSD):

Update: Adicionei um gerador de “Lorem Ipsum” tabajara ao programa. 🙂

O programa foi desenvolvido para Python 3, mas funciona em Python 2.6 ou 2.7 desde que você não se importe com acentuação errada (ou retire a lista de acentuação) :P, já que o símbolo de string unicode u“minha string não existe em Python 3 pois todas elas já são unicode por padrão.

Rodando o comando abaixo, onde 6 significa o número de letras e 5 o número de palavras geradas, você vai ter uma lista de palavras aleatórias, mas possíveis de serem ditas. Eventualmente, palavras reais aparecem.

~$ ./namegen.py 6 5

  zaraép
  carace
  coaiwi
  jegoãe
  czerab

Abaixo, um texto com 3 parágrafos gerados. Pode ser usado –lorem ou -l (L minúsculo) para isso.

~$ ./namegen.py --lorem 3

    Geraépeom phuraxoiao. Basaai 5 saczeiube! Êusoschuiac faiuveh gehotpe, zoou... ziamo, aetpeutqu. Ja e e voiauai chis fauoioioaee, dinh ënicze hotiafeo? Maeraraiouz gixarao. Hutfa, taçabanaaró quaphuiuerr: Quautqua czerrecoj talhe 69 ch jizoetpeumx chu laervalhu 23 ceçahat pib limeç cen, poiubihi rez.

    Jaz zazoc ke, psapovaoia! Psameoscz - íloiaõ, oczeruaru e, xyiaxaysum tioiaioosa: Tum íëumd, queat maer tegieoupo íczaeçapa czenaair éhotoise kez, zaãàaisaai, seenhaj, 5% gaoaülheiu énaízejaço, czewia... dauumoirara, riom. Darausoi, xeoucoero fezaaio ruzaousapa huta neum? E chapuuúpo nodisaiaos 9836.

    E chekodowoz fus eaixywoch, nebahatoiía hitiazelh moars sagelheha, jag. Óraoasessuu gageourreoo & chazioiai lagaviis loiaesbo deor xeraa, ciczai, hotraje & hat ga.

Observação:
A probabilidade é um valor inteiro qualquer que é o peso da seção. O cálculo é feito escolhendo um valor dentro da soma de todas as probabilidades (Não precisa somar 100%).

Ainda tem umas coisas para melhorar, como documentar as funções e classes, mas já foi bastante coisa para um projeto de um dia.

Possibilidades de utilização:
– Criar nomes inexistentes para projetos.
– Dificultar a leitura do seu programa, gerando o nome das variáveis assim.
– Fazer seu filho ser zoado no colégio, caso o nome dele seja Zaraép Jegoãe da Silva.

Até o ano que vem!