Postagem em destaque

Controle PID de Potência em Corrente Alternada - Arduino e TRIAC - Parte I

Este post é o primeiro de uma série de seis que escrevi tratando de controle de potência e PID (controle proporcional, integral e derivativo...

domingo, 15 de novembro de 2015

Conectando o PC e o Raspberry Pi via cabo de rede, SEM roteador no meio




Pois é, desde setembro que não rolava um post aqui por esses lados, mas o fato é que eu estou fazendo CINCO matérias do mestrado ao mesmo tempo e, por isso, não tenho tido tempo prá mais nada além de estudar, numa rotina que começa às CINCO da matina e termina por volta da meia-noite todos os dias.

Semana passada, porém, o amigão Thiago passou cá em casa para almoçar conosco, ele e D Estelinha, digníssima cara-metade. Como ele trouxe o seu Pi 2 recém adquirido para que a gente preparasse ele para rodar, assim fizemos. Ele quer trabalhar num projeto para automatizar todos os controles remotos da casa dele no celular, então fizemos também alguns testes (que funcionaram, depois de muita surra!) do uso daqueles receptores de controle remoto tipo NEC com o Pi. Sobre esse assunto vai rolar um post tb, mas como ainda não terminamos, fica prá depois.

Acontece que o Thiagão, na sua infinita gentileza largou cá em casa a título de empréstimo o seu Pi 2, de modo que hoje eu resolvi dar uma pausa nos estudos e "raspberriar" um pouco, até porque estou envolvido num projeto muito interessante e inovador sobre o qual ainda não posso escrever.

Um problema de trabalhar com o Pi é ter que levar teclado, mouse e principalmente monitor para onde a gente queira brincar. A gente pode até acessá-lo remotamente, mas tem que colocá-lo na rede do destino e alterar os parâmetros de wifi, consequentemente. Aí sem monitor não rola.

E se a gente conectasse o bicho no notebook sem a ajuda de um roteador? Será que é possível? Google prá lá e prá cá... bingo! Fiz o procedimento abaixo, que funcionou perfeitamente e é parecido com o que o cara escreveu aí:

1) Primeiro conferi no meu PC se o IP é automático ou manual. Era automático. Nesse caso, abra uma janela do DOS e dê o comando:


ipconfig

Anote o ip do seu micro no wifi e também a máscara de sub-rede coreespondente.

2) Editei o arquivo que ele indicou. Para isso, ele oferece dois caminhos, um mais simples e outro que implica em tirar o cartão do Pi etc. Fiz o mais simples:

sudo nano /boot/cmdline.txt

Esse arquivo tem uma linha só e tem que continuar assim, ou seja, qualquer coisa que vc for adicionar coloque no fim da linha e NÃO dê enter depois. Vc deve colocar no fim da linha um espaço e então ip=<número do ip do Pi>

3) Agora entra a escolha do <número do ip do Pi>. Se o IP do seu micro for automático, vc deve colocar um ip válido da faixa do seu roteador wifi que fornece o IP para o seu micro.

 Se for manual, vc tem que criar o IP do Pi respeitando as dicas que ele dá, basicamente tem que ser um IP válido com a máscara que está especificada no PC

Exemplo: se o IP do PC for 192.168.0.123 e a máscara de sub-rede for 255.255.255.0, use um IP como 192.168.0.200.

4) Em seguida, conecte o PC e o Pi através do cabo ethernet. Esse cabo éum cabo comum, antigamente seria preciso um cabo especial invertido, mas os adaptadores de rede hoje fazem eles mesmo a conexão invertida, necessária para esse tipo de conexão.

5) Reinicie o Pi. Imagino que vc tenha um monitor conectado a ele nesse ponto, então vc vai ver que ele demora uns 30 s para ativar a conexão via cabo.

6) Agora, para acessar o Pi vc pode usar o Putty, o Remote Desktop Connection caso tenha configurado esse tipo de acesso, para acessar o seu Pi.

Piece of cake, isn't it?

domingo, 6 de setembro de 2015

Startup Maker Weekend UNIFEI - Itajubá, MG

Fim de semana passado, 29,30 e 31 de agosto, participei do Startup Maker Weekend promovido pela UNIFEI. Foi o primeiro Startup Maker Weekend da América Latina. Outros já tinham acontecido, mas focados somente em software.

Devo dizer que a experiência foi... impactante!

54 horas de trabalho, cerca de 150 competidores, noss otime ficou num honroso terceiro lugar.

Os trabalhos começaram na sexta ali pelas 19, e foram até ali pela 1 da matina do sabadão. Aí, voltamos às 8 da matina e... eu fiquei dentro da UNIFEI trabalhando até meia-noite de domingo!

Dormi das 4:30 da matina até ali pelas 6 da manhã do domingão, no carro, no frio itajubense de 9°C.

O modelo do evento é muito legal:

- Primeiro as pessoas apresentam idéias. Quem tiver uma que apresente, em no máximo um minuto.

- Na apresentação vc tem que dizer qual o time vc gostaria de montar para completar as suas competências. Ex: eu dei uma ideia, como sou maker precisava de programador web, designers e gente de marketing.

- Em seguida as ideias foram relacionadas em cartazes e colocadas em uma parede, para que votássemos nas três que mais nos agradassem (colando uma espécie de "estrelinha" nas ideias).

- Os donos das quinze mais votadas foram então tentar montar os seus times, de até 10 pessoas, para desenvolver a ideia.

- Em seguida, vinha uma etapa de planejamento, com um canvas adequado.

- Aí terminou a sexta-feira.

- No sabadão, café da manhã e bora trabalhar!

A ideia é produzir não só um gadget mas também um modelo de negócios, com pesquisa de mercado, marca, preço e modelo de vendas, E assim fizemos. O povo foi a campo fazer pesquisa de mercado, inclusive.

Fim à disposição mentores técnicos, de marketing, de finanças, Pudemos pedir a ajuda deles quando necessário

- Ao fim dos trabalhos ocorre uma espécie de "feira", onde os produtos são expostos em bancadas para avalização da comissão julgadora.

- No domingo à noite cada grupo tem três minutos (!) para fazer uma apresentação de seus resultados, seguidos de quatro minutos de perguntas.

- Aí a comissão julgadora se reúne e anuncia os vencedores.

Nosso time, com os joseenses Fábio e André ficou em terceiro lugar.

O Cristian, tb joseense, levou menção honrosa, ou seja, São José fez bonito!

Abaixo, imagens do envento:

Nosso timaço de craques!


Mentor trabalhando

Fomos "às compras", escolher os componentes que usaríamos













Nosso time, quaaase completo na foto
















Hora do rango

A turma foi dividida em duas salas: essa, a nossa.

Traquitana voadora com Gopro, transmitindo imagens em tempo real

André trabalha

...

Nossa mesa

Salas dos outros makers

Voltando para o trabalho, às seis da manhã...



Esse negócio de ser maker dá uma fome...



Na madrugada nossa sala tava mais animada...

A galera já de volta aos trabalhos



Gabi e nosso mascote





















Nossos planos

As próximas três foram na tal "feira" de que falei acima


















Por fim, imagens da nossa premiação
























Por fim, timelapse que o Fábio fez com sua Gopro... reparem no sono do Everson, na madrugada...



Olha... foi muuuuuuuiiittttoooo bom! A turma que organizou lá da UNIFEI é nota dez, o povo tem a manha de fazer esse tipo de evento.

Os espaços que usamos ficaram por nossa conta, ou seja, a UNIFEI entregou a chave para a galera da organização.

Mais uma vez, o nosso time foi 10! Competência, empenho, esforço... nada faltou.

Foi simplesmente o melhor evento maker do qual já participei.

É isso.



domingo, 2 de agosto de 2015

Hackaton CI&T

No dia 25/05 participamos de hackaton think.make.move(), promovido pela CI&T, aqui em São José dos Campos.

O evento foi muito legal, com uma infra boa e a equipe da CI&T motivou bastante os times com brincadeiras. O lanche ótimo, enfim, nota dez prá infra do evento.

O tema do evento foi sustentabilidade e água. Fomos estimulados a produzir soluções que ajudassem a otimizar e reduzir o consumo de água em SP. Foi nos fornecida uma API para acessar dados de pluviômetros e também poderíamos acessar outros serviços de dados a respeito do consumo e disponibilidade de água.

Nosso time, composto por mim, Damião, Cristian, Euclides e Carlos, usou o nosso mascote SabugoEye para criar um equipamento de monitoramento em tempo real do volume de água de uma represa.



A ideia é instalar a maquininha na beira da represa para que ela possa disponibilizar dados e imagens a respeito.

O site foi feito com Unity, plataforma da Microsoft para desenvolvimento de games e sites com alta performance visual web e mobile. Ficou muuuuiiito bom, graças à habilidade do Damião e do Cristian. Eu e o Euclas fizemos a parte arduínica da coisa, dando à câmera movimento para que ela pudesse ser usada para visualizar diferentes ângulos da represa.

Os fontes da parte Unity podem ser baixados pelos interessados clicando aqui. O site está ocasionalmente no ar aqui:

Abaixo, fotos do evento. Que venham mais desses!!!



Abaixo uma RepRap que os caras levaram, feita com estrutura acrílica. E aí, Fabião???


Abaixo, vídeo do SabugoEye funcionando.

video


domingo, 7 de junho de 2015

Intel Edison tips - I

Algumas dicas legais que fui aprendendo sobre o Edison.

Como instalar o nano

O editor de textos que vem com ele é o vi, não seu se tem outro. Como eu não consigo me ajeitar com esse camarada, pesquisei se tinha jeito de instalar o nano, que eu uso no RPi.

Mole:

- Crie um diretório nano
- Vá lá prá dentro (cd nano)
- Com o seu micro conectado à internet, dê o seguinte comando

wget http://www.nano-editor.org/dist/v2.2/nano-2.2.6.tar.gz && tar xvf nano-2.2.6.tar.gz && cd nano-2.2.6 && ./configure && make && make install
Dica dentro da dica:

Para dar esse comandão não precisa digitá-lo. Copie com Ctrl-C e, se vc estiver usando o Putty como programa de terminal, é só clicar com o botão direito na frente do prompt do Linux e o Putty "descarrega" o comando lá.

Aí é só dar enter.

Como ganhar mais uma partição de 800 Mb no Edison

O Edison mantém uma cópia da imagem do Yocto (Linux do Edison) no disco. Vc pode disponibilizar esse espaço numa novo drive.

Para isso:

// Cria o novo sistema de arquivos
# mkfs.ext4 /dev/disk/by-partlabel/update

// edite o arquivo /etc/fstab, colocando numa só linha o comando abaixo
# nano /etc/fstab
/dev/disk/by-partlabel/update     /mnt      auto    noauto,x-systemd.automount,,
nosuid,nodev,noatime,discard,barrier=1,data=ordered,noauto_da_alloc 1   1

// Monte o drive e check o espaço em disco
# mount /mnt
# df -k
...
/dev/mmcblk0p9          757680       776    701856   0% /mnt


Taí!

Site legal

Na net ainda tem pouco material sobre o Edison, comparando com outras plaquinhas. De vez em quando a gente topa com um site de dicas bem legal.

Esse aqui é um deles. Lá que eu vi essa última dica, por lá tem outras:
http://www.helios.de/heliosapp/edison/index.html#Get_additional_800_MB_disk_space

Dicas sobre Bluetooth e backup no Edison

http://rwx.io/blog/2015/02/18/seting-up-an-edison/


Recuperando o Intel Edison

Estou tentando aumentar o espaço da partição root do meu Edison para instalar o OpenCV. "Niqui" eu fui mexendo, acabei detonando o bicho, que simplesmente não conseguia terminar o boot. Será que foi porque eu deletei um monte de arquivos do raiz??? ;)

Bom, pesquisa dali, pesquisa dali, achei uma dica que funcionou. Logo no início do boot aparece uma mensagem:

Hit any key to stop boot

Ela não espera nada, então vc tem que apertar a tecla muito rapidamente.

Aí aparece um prompt >

Em seguida, execute o comando:

run do_ota

Ele recupera a imagem original do Edison.

A má notícia, claro, é que vc perderá tudo o que tinha antes da recuperação do Linux.

quinta-feira, 4 de junho de 2015

Intel Edison - Configurando WiFi

Colocar o Edison na sua rede wifi é mole. Para isso:

1) Conecte-se ao Edison pela porta serial. Como? Leia aqui, https://software.intel.com/en-us/node/541767, um post meu no blog da Intel que explica como.

2) Uma vez logado, dê o seguinte comando:

configure_edison --wifi

Após algum tempo, em que ele pesquisará as redes wifi disponíveis, aparecerá a tela abaixo:

Escolha a rede em que deseja conectar digitando o número à esquerda do nome dela e apertando ENTER.

No meu caso, 9 (HOMENET).

Ele pede uma confirmação, vc confirma (Y ENTER) e ele pedirá a senha, que é a senha de conexão ao seu wifi.

Após fornecer a senha, o Edison vai tentar se conectar à sua rede wifi.

Se tudo deu certo, aparecerá a seguinte mensagem:

Done. Please connect your laptop or PC to the same network as this device and go to http://192.168.0.106 or http://EdisonMauro.local in your browser.
Warning: SSH is not yet enabled on the wireless interface. To enable SSH access to this device via wireless run configure_edison --password first.

Se não... tente o comando configure_edison --wifi de novo, pode ser que vc tenha digitado a senha errada.

Por fim acesse a página que ele recomenda (http://192.168.0.106) e veja uma tela com as informações do "seu Edison":


É isso. Piece of cake, isn´t it?

sábado, 23 de maio de 2015

Usando o LeapMotion para controlar um robô meArm I

Abaixo, o vídeo dos meus primeiros resultados controlando o meArm a partir do sensor LeapMotion.


Esse sensor é semelhante ao Kinect, ou seja, detecta movimentos do nosso corpo (no caso, somente as mãos e braços) e constrói, usando modelos matemáticos bastante complexos, um modelo 3D que descreve cada parte do que está em seu "campo de visão". Essa detecção é feita com emissão e captação de radiação infravermelha.

Como a matemática por trás do troço é muito complexa, ele precisa do PC, ou seja, ainda não é possível ter uma plaquinha das que a gente usa (Arduino, RPi, Edison etc) para processar diretamente os sinais enviados pelo sensor.

Dito isso, se quisermos comandar algum device com o LM, devemos estabelecer a comunicação entre o PC onde o LM está conectado e o dispositivo a ser comandado.

No caso, a ideia é estabelecer uma maneira de comandar o meArm (pequeno robô visto no vídeo acima) de forma total, ou seja, todos os movimentos, a partir de movimentos captados pelo LM em uma ou duas mãos.

Como o robô pode ser controlado com um Arduino, pensei em ligar o Arduino no PC, captar os movimentos do meArm com uma aplicação em Python, processar esses comandos para facilitar o comando pelo Arduino e enviar pro Arduino via porta serial.

Os primeiros testes, me pareceu óbvio, seriam mais fáceis com a pinça, ou seja, fechando e abrindo a pinça do robô com movimentos em pinça do polegar contra o indicador.

Esse post vai tratar de como isso foi feito.

Primeiro, vamos analisar a aplicação Python:

###############################################################################
#                                                                             #
# This program tests the tweezers movement in meArm controlled by Leap Motion #
# You can see more in http://automatobr.blogspot.com.br                       #
#                                                                             #
# assismauro@hotmail.com                                                      #
#                                                                             #
###############################################################################
import sys
# Bring serial stuff
import serial
import thread, time

# Add path to LeapMotion libs directory 
sys.path.insert(0,"D:\Atrium\Projects\Arduino\LeapMotion\lib")

# import LM stuff
import Leap
from Leap import CircleGesture, KeyTapGesture, ScreenTapGesture, SwipeGesture

# initialize Arduino/PC communication. You must set COM port accordingly your Arduino connection
arduino = serial.Serial('COM45', 9600, timeout=.1)

# This listener is called anytime some data is available form LM
class SampleListener(Leap.Listener):

# some readable names to use later
    finger_names = ['Thumb', 'Index', 'Middle', 'Ring', 'Pinky']
    bone_names = ['Metacarpal', 'Proximal', 'Intermediate', 'Distal']

    def on_init(self, controller):
        print "Initialized"

    def on_connect(self, controller):
        print "Connected"

    def on_frame(self, controller):

        global arduino

        # Get the most recent frame, that contains data sent from LM engine
        frame = controller.frame()

        # Get hands
        if len(frame.hands) == 0:
            return
        
        hand = frame.hands[0] # only one hand

        # Get fingers: we only need Thumb and Index data, for a while
        for finger in hand.fingers:
            if (self.finger_names[finger.type()] == "Thumb") or (self.finger_names[finger.type()] == "Index"):
            # Get bones
                for b in range(0, 4):
                    bone = finger.bone(b)

                    d=0.0
                    i=0.0
                    tshMin = 10.0
                    tshMax = 100.0
                    # The idea is to process only distal bone data, that corresponds to te tip of our fingers.
                    # The LM coordinate system is a X,Y,Z based in the center of the sensor (see picture in my
                    # blog). As we need only the distance between tips, in a tweezers movement, I transform it
                    # in a "percent distance", that is, 0 corresponds to tweezer closed, and 100, tweezer
                    # oppened.
                    if (self.bone_names[bone.type] == "Distal"):
                        if (self.finger_names[finger.type()] == "Thumb"):
                            t=bone.next_joint[0]
                        else:
                            i=bone.next_joint[0]
                            d=abs(t-i)
                            o=100 if d >= tshMax else (0 if (d <= tshMin) else (d-tshMin)/tshMax*100.0)
                            print o
                            # here we send data to Arduino
                            toSend = str(o)+"\n"
                            arduino.write(toSend)
                            # and... that´s it.

def main():
    # Create a sample listener and controller
    listener = SampleListener()
    controller = Leap.Controller()
     
    # Have the sample listener receive events from the controller
    controller.add_listener(listener)

    # Keep this process running until Enter is pressed
    print "Press Enter to quit..."
    try:
        sys.stdin.readline()
    except KeyboardInterrupt:
        pass
    finally:
        # Remove the sample listener when done
        controller.remove_listener(listener)

if __name__ == "__main__":
    main()

O código acima, devidamente comentado, é responsável por enviar ao Arduino os comandos do motor da pinça (garra) do meArm.

Abaixo, o programa que roda no Arduino:


/*
  Program to command meArm gripper from LeapMotion (Arduino side)
  More about that: http://automatobr.blogspot.com.br
  assismauro@hotmail.com
*/

#include <Servo.h>
#include <SoftwareSerial.h>

// Debug communication, if you think is necessary
SoftwareSerial mySerial(7,8);

// meArm servo pins
int basePin = 11;
int shoulderPin = 10;
int elbowPin = 9;
int gripperPin = 6;

Servo base;
Servo shoulder;
Servo elbow;
Servo gripper;

void setup() {
  /*
  base.attach(basePin);
  shoulder.attach(shoulderPin);
  elbow.attach(elbowPin);
  */
  // Gripper test
  gripper.attach(gripperPin);
  Serial.begin(9600);
  mySerial.begin(9600);
  gripper.write(90);
  delay(500);
  gripper.write(120);
  delay(500);
  
}

// Stores the last cmd received
int cmdOld=-1;

// Threshold
int limiar = 5;

void loop() 
{
  String cmdStr = "";
  // Get command from Pyton PC app
  if(Serial.available())
     cmdStr=Serial.readStringUntil(10);
  
  if(cmdStr != "")
  {
     int cmd=cmdStr.toInt();
     //Check threshold
     if((cmd > 100) || (abs(cmd - cmdOld) < limiar))
        return;
     cmdOld=cmd;
     // Map LeapMotion command to gripper servo angle   
     int gripAngle=map(cmd,0,100,140,90);
     gripper.write(gripAngle);
     delay(30);
     // Send data to debug Arduino
     mySerial.print(cmd);
     mySerial.print("  -  ");
     mySerial.println(gripAngle);
  }
}

O programa é bem simples: recebe o comando que vem do Python e o trata, acionando o motor da garra.

Dois detalhes importantes:

1) Vc pode observar que tem a definição de uma segunda porta serial. Eu fiz isso para depurar o meu programa, porque como a porta serial que normalmente a gente usa para se comunicar com o Arduino está ocupada pelo próprio. Aí eu liguei um segundo Arduino a outro PC e conectei os dois criando uma porta serial usando os pinos 7 e 8. Aí deu para monitorar os comandos que estavam chegando enviando-os ao outro Arduino.

2) Outro pronto é a variável limiar.  Ela serve para suavizar os movimentos do meArm, porque os comandos recebidos variam muito. Isso evita a "tremedeira" da garra.

É isso.


Relógio de Tempo Real - RTC: o que é e quando é necessário usar

Um amigo, o Rodrigo, está montando no sítio um sistema de irrigação automática controlado por Arduino. Conversando sobre o projeto, sugeri a ele que comprasse um RTC, já que saber a hora do dia e mesmo o dia da semana é importante nesse tipo de projeto.

Aqui no blog tem um post que ensina inclusive como montar um RTC. Acontece que, como é parte de um outro projeto, acabou que não se falou muito do RTC. Principalmente não se falou das aplicações do bicho, o que é um pecado tendo em vista a importância do dito.

 Agora vai:
Image result for bateria de relógioRTC (Real Time Clock) é um dispositivo que armazena a data e a hora de maneira precisa ao longo do tempo. É um relógio, onde vc indica a data/hora inicial e ele passa a contar o tempo a partir daí. Ele tem uma bateria para manter a data/hora de maneira que, se o equipamento a que está conectado ficar sem alimentação, ao ser religado a hora está certa.

Esse dispositivo existe dentro de muitos aparelhos, como relógios digitais, despertadores, fornos de microondas etc. A bateria que eles usam, aquela que parece uma moeda (essa aí do lado), até tem o apelido de "bateria de relógio" por isso.

E para que a gente precisa disso no Arduino? Basicamente para três funções:

1) Quando precisamos que a data/hora seja mantida correta entre desligamentos do Arduino.

Quando a gente desliga o Arduino, o "pograminha" permanece em sua memória, mas ele para de rodar. Assim, se vc tiver um contador de tempo no seu programa (a função millis() é usada para esse fim), ele começará do zero quando for religado. Aí entra o RTC, obviamente.

2) Para manter a data/hora de um equipamento ao longo de muitos dias, ou meses.

A função millis() funciona assim: a cada milésimo de segundo o Arduino incrementa um contador interno de uma unidade. Assim, quando acessamos millis() a função retorna esse número.

Acontece que o maior número inteiro que o Arduino armazena é o que é conhecido no C como unsigned long, que é um número de 32 bits, ou seja 4 bytes.

Isso significa que o maior número inteiro que o Arduino consegue armazenar é 232, ou seja, 4.294.967.296 milissegundos. Parece muito, mas:

Um dia tem 3600 s/h * 1000 ms/s * 24h/d = 86.400.000 ms/dia.

Ou seja, o Arduino tem como contar tempo durante 4.294.967.296 ms/(86.400.000 ms/dia), ou seja, 49.7 dias, ou menos de dois meses, o que é pouco para sistemas que funcionarão durante anos.

E o que acontece quando chega no fim, quer dizer, se a gente vai acessando a função millis() e passam-se os tais quase 50 dias? "Tio, O Arduino explode???? ", perguntaria vc, aflito. Não, a variável simplesmente zera e começa a contar de novo.

3) Quando precisamos de uma medida do tempo precisa.

A função millis() é de uma precisão bastante razoável quando queremos contar o tempo em alguns segundos. Acontece que tem algumas funcionalidades do Arduino que distorcem essa função, ou seja, fazem com que ela passe a dar valores menos precisos. Uma dessas funções são as interrupções, que já foram discutidas aqui. Quando o programa principal "congela" para executar uma interrupção ele também congela o incremento da variável do millis() fazendo que a função perca em precisão, "aumentando o tamanho" de um segundo.

Bom, essas são as três razões principais pelas quais vc deve usar um RTC quando for precisar de uma medida de tempo. No mais, vc pode ir de millis() mesmo que estará de bom tamanho.

O funcionamento

O RTC mais simples é baseado em um chip chamado DS1307. Na realidade é uma família de chips, todos com código semelhante a esse, que é um chip especializado, quer dizer, feito para esse fim.

Ele basicamente armazena o valor do tempo que, uma vez inicializado, vai sendo incrementado com muita precisão pelo chip. É necessária ainda uma bateria tipo relógio, aquela da foto aí em cima, para manter a data/hora, e também uma alimentação de 3 a 5V para que possamos nos comunicar com o chip, de maneira a preservar a bateria que fica com o fim exclusivo de manter a contagem de tempo.

Diz o fabricante que o consumo de chip é da ordem de pico Ampère, quer dizer, 10-9A. Segundo os caras, a bateria consegue manter a coisa precisa por mais de 6 anos (!). Parece um adaptador de tomadas que tem lá em casa que diz que funciona em mais de 200 países, ou seja, difícil de comprovar. Na África do Sul, por exemplo, não funciona.

Mas.. tergiverso, voltemos ao que interessa.

"Bom,tio, e cumé que usamos essa bagaça?"

Piece of cake:

arduino to RTCAcima esquema de um break RTC ligado ao Arduino. Break é quando a gente tem um dispositivo que já vem mais "mastigado", ou seja, devidamente soldado e com pinos para que a gente o conecte ao mundo externo. "É a mesma coisa que shield então né?" Não, nénão. Shield é o break que se encaixa em cima do Arduino, ou seja, todo shield é um break mas nem todo break é shield, como é o caso do RTC.

 As conexões principais, ou seja, as que são obrigatórias para o RTC funcionar são:

GND e Vcc: alimentação, positivo e negativo, fios azul e vermelhor acima.
SDA e SCL: comunicação entre o Arduino e o break. É por esses fios que os dados vão e vem entre os dois dispositivos, num protocolo chamado i2c, que já foi usado em outros projetos aqui do blog.

O Arduino se comunica via i2c usando as portas A4 e A5 analógicas, que devem ser conectadas aos pinos SDA e SCL do Arduino.

Além dessas conexões podem haver outras. Existem breaks RTC que vem com um sensor de temperatura, tipo LM35 ou outro semelhante. Nesse caso vc o conecta a uma entrada/saída digital do Arduino, conforme mostrado na conexão DS/pino 2 acima.

Existe também um meio de vc saber se a bateria está ou não ok, através do pino BAT indicado acima.

Conectado o break, faça o upload do "pograminha" abaixo. Eu fiz o download o modifiquei apenas um pouco, então vai com o crédito do sujeito que fez. A vantagem dessa implementação é que a única biblioteca que ela usa é a Wire.h, que já vem quando a gente instala o Arduino. Existem algumas libs prontas que facilitam (RTCLib é uma delas), então fica a seu gosto decidir como usar.

Basicamente ele faz duas coisas:

1) Permite que vc acerte o relógio

2) Uma vez acertado, ele passa a mostrar a hora correta (essa foi a minha alteração).

Para verificar se está tudo ok com o break, rode o programa e forneça a data/hora corretas. Em seguida, desligue o Arduino e ligue novamente. Quando o programa perguntar se que vc quer atualizar data/hora, responda que não. Se ele voltar a indicar a hora correta, vc é o feliz proprietário de um RTC que funciona!

Abracadabraço,

Mauro

///////////////////////////////////////////

// RTC data and time setter              //
//                                       //
// This sample program allows the user   //
// to set the date and time of an RTC    //
// using I2C.                            //
//                                       //
// Codes by:                             //
// eGizmo Mechatronix Central            //
// Taft, Manila, Philippines             //
// http://www.egizmo.com                 //
// April 15, 2013                        //
///////////////////////////////////////////

#include <Wire.h>

const int DS1307 = 0x68; // Address of DS1307 see data sheets

const char* days[] =
{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

const char* months[] =
{"January", "February", "March", "April", "May", "June", "July", "August","September", "October", "November", "December"};

// Initializes all values:
byte second = 0;
byte minute = 0;
byte hour = 0;
byte weekday = 0;
byte monthday = 0;
byte month = 0;
byte year = 0;

void setup() {
  Wire.begin();
  Serial.begin(9600);
  delay(2000); // This delay allows the MCU to read the current date and time.

  Serial.print("The current date and time is: ");
  printTime();
  Serial.println("Please change to newline ending the settings on the lower right of the Serial Monitor");
  Serial.println("Would you like to set the date and time now? Y/N");

  while (!Serial.available()) delay(10);

  if (Serial.read() == 'y' || Serial.read() == 'Y')
  // This set of functions allows the user to change the date and time
  {
    Serial.read();
    setTime();
    Serial.print("The current date and time is now: ");
    printTime();
  }
  Serial.println("Thank you.");
}


// Continuous function for converting bytes to decimals and vice versa
void loop() {
  readTime();
  printTime();
  delay(1000);
}

byte decToBcd(byte val) {
  return ((val/10*16) + (val%10));
}

byte bcdToDec(byte val) {
  return ((val/16*10) + (val%16));
}

void setTime() {
  Serial.print("Please enter the current year, 00-99. - ");
  year = readByte();
  Serial.println(year);
  Serial.print("Please enter the current month, 1-12. - ");
  month = readByte();
  Serial.println(months[month-1]);
  Serial.print("Please enter the current day of the month, 1-31. - ");
  monthday = readByte();
  Serial.println(monthday);
  Serial.println("Please enter the current day of the week, 1-7.");
  Serial.print("1 Sun | 2 Mon | 3 Tues | 4 Weds | 5 Thu | 6 Fri | 7 Sat - ");
  weekday = readByte();
  Serial.println(days[weekday-1]);
  Serial.print("Please enter the current hour in 24hr format, 0-23. - ");
  hour = readByte();
  Serial.println(hour);
  Serial.print("Please enter the current minute, 0-59. - ");
  minute = readByte();
  Serial.println(minute);
  second = 0;
  Serial.println("The data has been entered.");

  // The following codes transmits the data to the RTC
  Wire.beginTransmission(DS1307);
  Wire.write(byte(0));
  Wire.write(decToBcd(second));
  Wire.write(decToBcd(minute));
  Wire.write(decToBcd(hour));
  Wire.write(decToBcd(weekday));
  Wire.write(decToBcd(monthday));
  Wire.write(decToBcd(month));
  Wire.write(decToBcd(year));
  Wire.write(byte(0));
  Wire.endTransmission();
  // Ends transmission of data
}



byte readByte() {
  while (!Serial.available()) delay(10);
  byte reading = 0;
  byte incomingByte = Serial.read();
  while (incomingByte != '\n') {
    if (incomingByte >= '0' && incomingByte <= '9')
      reading = reading * 10 + (incomingByte - '0');
    else;
    incomingByte = Serial.read();
  }

  Serial.flush();
  return reading;
}


void printTime() {
  char buffer[3];
  const char* AMPM = 0;
  readTime();
  Serial.print(days[weekday-1]);
  Serial.print(" ");
  Serial.print(months[month-1]);
  Serial.print(" ");
  Serial.print(monthday);
  Serial.print(", 20");
  Serial.print(year);
  Serial.print(" ");
  if (hour > 12) {
    hour -= 12;
    AMPM = " PM";
  }
  else AMPM = " AM";
  Serial.print(hour);
  Serial.print(":");
  sprintf(buffer, "%02d", minute);
  Serial.print(buffer);
  Serial.print(":");
  sprintf(buffer, "%02d", second);
  Serial.print(buffer);
  Serial.println(AMPM);
}


void readTime() {
  Wire.beginTransmission(DS1307);
  Wire.write(byte(0));
  Wire.endTransmission();
  Wire.requestFrom(DS1307, 7);
  second = bcdToDec(Wire.read());
  minute = bcdToDec(Wire.read());
  hour = bcdToDec(Wire.read());
  weekday = bcdToDec(Wire.read());
  monthday = bcdToDec(Wire.read());
  month = bcdToDec(Wire.read());
  year = bcdToDec(Wire.read());
}

terça-feira, 21 de abril de 2015

Automação no Parque, 18/04/2015

O Automação no Parque está vivendo um bom momento, com alguns projetos desafiadores rolando.

Logo cedo (7:00) chega a Alessandra, que está se inciando com o Arduino. Ela tem que ir embora antes das nove pro trabalho, por isso madruga. Estamos fazendo oficinas básicas de Arduino.


Tem o Rodrigo, com o seu projeto de sensores para a indústria do qual já andei falando e sobre o qual falarei mais na frente.

Tem uma dupla, o Alex e o Carlos (kbca) que estão fazendo coisas muito legais com o LeapMotion, que é nada mais nada menos que um detector de movimentos das mãos que permite o comando de aplicações (jogos etc) no computador usando-se o movimento das mãos.

Os caras estão fazendo um jogo de JoKenPo  (pedra-papel-tesoura), e o PC já tá ganhando todas!

Tem também o Fábio com o seu braço robótico, cortado por ele mesmo em sua máquina de corte à laser:




Quem quiser comprar um ele vende, viu galera? É um "brinquedo" e tanto, e dá cada TCC... ;)

Outro projeto que apareceu por lá é o do Filipe, que quer comandar uma mão robótica (que ele imprimiu numa impressora 3D) através de sinais elétricos captados no braço de uma pessoa. Assim, uma pessoa que não tivesse uma das mãos (ou as duas) poderia manipular objetos usando o device que ele está construindo.


No projeto do Filipe surgiu uma demanda intessante: a mão é comandada por dois servos, um aciona os quatro dedos "compridos" e o outro o dedão. Aí já dá para fazer os movimentos de "pegar" e de "pinça".

Supondo que um determinado movimento implique em acionar num dos motores (chamemos de motor1) de maneira a sair da posição em que se encontra (digamos, 30°, p1) até a posição 100°, np1, enquanto que o motor2 tem que sair de 120° (p2) para 90° (np2).

A saída fácil seria acionar motor1 para se mover da posição p1 até np1 e depois motor2 de p2 até np2.

Ocorre que a gente não move os dedos dessa forma, ou seja, primeiro os quatro e depois o dedão, mas sim todos os cinco simultaneamente.

O desafio, então, é: girar os dois motores simultaneamente de suas posições iniciais até as finais de maneira a que o movimento termine simultaneamente. Ou seja, como motor1 tem que girar 70° e motor2 tem que girar apenas 40° (e na direção contrária), o motor1 tem que se movimentar mais devagar que o motor2.

Após quebrar a cabeça por um tempo, construímos a função posiciona que aparece no programa abaixo:
#include <Servo.h>

// assismauro@hotmail.com
// Ver vídeo em https://youtu.be/5d2tg_7dvi0)

Servo motor1;
Servo motor2;

int val;

// Função posiciona: gira dois motores simultaneamente de modo a
// atingirem suas novas posições simultãneamente
//
// np1: nova posição do motor1
// np2: nova posição do motor2
void posiciona(float np1, float np2)
{
  // Começamos lendo  posição atual de cada motor
  float p1=motor1.read();
  float p2=motor2.read();
  // Em seguida, calculamos a distância, em graus, entre as posições
  // atuais e as novas.
  // Observem que trabalhamos com variáveis float, para diminuir os
  // erros de arredondamento.
  float d1=np1-p1;
  float d2=np2-p2;
  // pc1 e pc2 são as posições correntes, que serão incrementadas 
  // durante o movimento.
  float pc1=p1;
  float pc2=p2;
  // Aqui tá o "pulo" do gato: São calculados s1 (passo do motor1) e
  // s2 (passo do motor2). Eles são o incremento que será dado a cada
  // movimento do motor. s1 será a razão entre d1 e d2, enquanto que
  // s2 será igual à razão entre d2 e d2 (ou seja, 1). Usamos valores
  // absolutos no denominador para preservar o sinal, ou seja, se d1
  // é negativo, s1 também será negativo.
  //
  // Ex:
  //
  // Suponhamos que d1 seja -50 e d2 seja 100. Nesse caso, s1=-0.5 e
  // s2=1. Ou seja, motor1 andará 0.5° para cada 1° que motor2 andar.
  // Ao fim do movimento motor2 terá girado o dobro do que 
  // girou o motor1.
  float s1=d1/abs(d2);
  float s2=d2/abs(d2);
  //
  // imprime os valores calculados, para debug, mostrando na tela
  // os valores calculados
  Serial.print(np1);
  Serial.print(' ');
  Serial.print(np2);
  Serial.print(' ');
  Serial.print(p1);
  Serial.print(' ');
  Serial.print(p2);
  Serial.print(' ');
  Serial.print(d1);
  Serial.print(' ');
  Serial.print(d2);
  Serial.print(' ');
  Serial.print(pc1);
  Serial.print(' ');
  Serial.print(pc2);
  Serial.print(' ');
  Serial.print(s1);
  Serial.print(' ');
  Serial.print(s2);
  Serial.println();
  // Aqui giramos os dois motores, até que ambos tenham assumido
  // a sua posição final, ou seja:
  // enquanto a diferença absoluta entre a posição atual e a nova
  // posição de cada motor for > 1, eu continuo girando.
  while((abs(pc1-np1) > 1) || (abs(pc2-np2) > 1))
  {
    // Somo o incremento à posição corrente de cada motor
    pc1=pc1+s1;
    pc2=pc2+s2;
    // Mostro os valores na tela
    Serial.print(pc1);
    Serial.print(' ');
    Serial.println(pc2);
    // Giro os motores para suas novas posições
    motor1.write(pc1);
    motor2.write(pc2);
    // Dou um tempo de 20 milissegundos para que os motores
    // atinjam a nova posição.
    delay(20);
  }
}

void setup()
{
  // Associo os motores aos pinos que estão conectados.
  motor1.attach(9);
  motor2.attach(10);
  // Inicializo a comunicação com o PC
  Serial.begin(9600);
  // Coloco os dois motores na posição 0
  motor1.write(0);
  motor2.write(0);
}

void loop()
{
  // Para demonstrar a rotina, o programa posiciona os
  // servos em diferentes ângulos.
  posiciona(90,45);
  delay(500);
  posiciona(178,90);
  delay(500);
  posiciona(45,10);
  delay(500);
  posiciona(145,60);
  delay(500);
}

Decidi explicar no código porque achei que talvez ficasse mais fácil.

Aqui o vídeo do programa rodando, acionando os motores:


DESAFIO: observando o código que escrevi e o vídeo vc saberia me dizer quem é o motor2 e quem é o motor1, e porque vc chegou a essa conclusão?

Respostas nos comentários abaixo.

Abracadabraço,

Mauro Assis



domingo, 15 de março de 2015

Raspberry Pi - acessando dados do Yahoo Weather a respeito do clima via Temboo

E no Raspberry, será que rola?

R: rola, e é o mesmo procedimento que fizemos no caso do Edison.

Apenas na hora dos comandos python setup.py build e python setup.py install devemos colocar o sudo antes:

sudo python setup.py build
sudo python setup.py install

Depois é só entrar no Python e testar, exatamente como fiz no Edison,

É isso.

Intel Edison - acessando dados do Yahoo Weather a respeito do clima via Temboo

Como no Yún não deu muito certo a ideia de acessar o Yahoo Weather pelo Python, surgiu a ideia: será que funciona  no Edison? Boralá!

Roteiro para usar a python-weather-api no Edison:

1) Faça o download dos arquivos necessários. Para isso, o Edison deve estar conectado à internet e vc deve acessá-lo via algum programa de terminal, por exemplo o Putty. Para ver como fazer isso, clique aqui.

2) Primeiro, crie um diretório para colocar os arquivos de instalação:

mkdir pywapiinstall
cd pywapiinstall

3) Baixe o arquivo contendo os arquivos de instalação:

wget --no-check-certificate 'https://launchpad.net/python-weather-api/trunk/0.3.8/+download/pywapi-0.3.8.tar.gz'

4) Descompacte o arquivo

tar -xvf pywapi-0.3.8.tar.gz

5) Mude para o dir onde foram descompactados os arquivos

cd pywapi-0.3.8 

6) Instale os arquivos

python setup.py build
python setup.py install

7) Em seguida, entre no python e faça o teste:

import pywapi
pywapi.get_weather_from_yahoo('BRXX0228')

E... não é que funcionou de prima? Veja aí o resultado:

{'html_description': u'\n<img src="http://l.yimg.com/a/i/us/we/52/30.gif"/><br />\n<b>Current Conditions:</b><br />\nPartly Cloudy, 30 C<BR />\n<BR /><b>Forecast:</b><BR />\nSun - Thunderstorms. High: 28 Low: 20<br />\nMon - PM Thunderstorms. High: 31 Low: 21<br />\nTue - Thunderstorms. High: 27 Low: 21<br />\nWed - Thunderstorms. High: 29 Low: 20<br />\nThu - PM Thunderstorms. High: 28 Low: 20<br />\n<br />\n<a href="http://us.rd.yahoo.com/dailynews/rss/weather/Sao_Jose_Dos_Campos__BR/*http://weather.yahoo.com/forecast/BRXX0228_c.html">Full Forecast at Yahoo! Weather</a><BR/><BR/>\n(provided by <a href="http://www.weather.com" >The Weather Channel</a>)<br/>\n', 'atmosphere': {'pressure': u'1015.92', 'rising': u'0', 'visibility': u'9.99', 'humidity': u'58'}, 'title': u'Yahoo! Weather - Sao Jose Dos Campos, BR', 'condition': {'date': u'Sun, 15 Mar 2015 1:01 pm BRT', 'text': u'Partly Cloudy', 'code': u'30', 'temp': u'30', 'title': u'Conditions for Sao Jose Dos Campos, BR at 1:01 pm BRT'}, 'forecasts': [{'code': u'4', 'text': u'Thunderstorms', 'high': u'28', 'low': u'20', 'date': u'15 Mar 2015', 'day': u'Sun'}, {'code': u'38', 'text': u'PM Thunderstorms', 'high': u'31', 'low': u'21', 'date': u'16 Mar 2015', 'day': u'Mon'}, {'code': u'4', 'text': u'Thunderstorms', 'high': u'27', 'low': u'21', 'date': u'17 Mar 2015', 'day': u'Tue'}, {'code': u'4', 'text': u'Thunderstorms', 'high': u'29', 'low': u'20', 'date': u'18 Mar 2015', 'day': u'Wed'}, {'code': u'38', 'text': u'PM Thunderstorms', 'high': u'28', 'low': u'20', 'date': u'19 Mar 2015', 'day': u'Thu'}], 'link': u'http://us.rd.yahoo.com/dailynews/rss/weather/Sao_Jose_Dos_Campos__BR/*http://weather.yahoo.com/forecast/BRXX0228_c.html', 'location': {'city': u'Sao Jose Dos Campos', 'region': u'', 'country': u'BR'}, 'units': {'distance': u'km', 'speed': u'km/h', 'temperature': u'C', 'pressure': u'mb'}, 'astronomy': {'sunset': u'6:19 pm', 'sunrise': u'6:05 am'}, 'geo': {'lat': u'-23.23', 'long': u'-45.83'}, 'wind': {'direction': u'220', 'speed': u'3.22', 'chill': u'30'}}

O código BRXX0228 corresponde a São José dos Campos. E como eu descobri isso? Nessa lista: https://www.edg3.uk/snippets/weather-location-codes/brazil/

Também é possível acessar outros serviços de previsão de tempo, bem como obter uma determinada informação em vez de toda essa string aí em cima. Abaixo, um exemplo:

# -*- coding: cp1252 -*-
import  pywapi
import string

weather_com_result = pywapi.get_weather_from_weather_com('BRXX0228')
yahoo_result = pywapi.get_weather_from_yahoo('BRXX0228')

print "Weather.com diz que agora o tempo esta " + string.lower(weather_com_result['current_conditions']['text']) + " e " + weather_com_result['current_conditions']['temperature'] + "C agora em Sao Jose dos Campos.\n\n"

print "Yahoo diz que agora o tempo esta " + string.lower(yahoo_result['condition']['text']) + " e " + yahoo_result['condition']['temp'] + "C agora em Sao Jose dos Campos."

O resultado? Abaixo:

Weather.com diz que agora o tempo esta partly cloudy e 30C agora em Sao Jose dos Campos.


Yahoo diz que agora o tempo esta partly cloudy e 30C agora em Sao Jose dos Campos.

Bom, é isso! Enjoy!