quarta-feira, 7 de setembro de 2011

pHmetro

Para quem não conhece, pHmetro é o aparelho utilizado para medir pH de líquidos. Ele é composto de um dispositivo de leitura e uma ponta de prova. Para montar um pHmetro baseado em arduino compramos o kit pH-stamp, da Atlas Scientific. O kit é composto pelo pH-stamp, a ponta de prova e uma solução de calibração. O pH-stamp é um circuito que faz a interface entre uma ponta de prova de pH e o arduino:
Ele possui 6 conexões:
  • Vcc - alimentação da placa (tensão: 3,3 - 5,5v);
  • GND - o bom e o velho terra do arduino;
  • PRB - Sinal da ponta de prova;
  • GND - Terra da ponta de prova;
  • Tx e Rx - Estas duas conexões são responsáveis pela comunicação com o arduino.
As 2 primeiras conexões são conhecidas e não há nenhum mistério nelas. As outras duas, PRB e GND, são conectadas a um conector BNC (conector de cabo coaxial, o mesmo da figura abaixo), sendo que o conector central corresponde ao PRB e o externo ao GND.
As outras duas conexões, Tx e Rx, serão conectadas em portas digitais do arduino. É importante lembrar que a porta Tx do pH-stamp deve ser conectada a porta Rx do arduino e vice-versa. Até aqui, tudo o que eu falei está no manual que veio junto com o kit. No manual tem um código arduino para Duemilanove. Este código não funciona com o arduino MEGA. Fiquei duas horas tentando achar algum erro e estava prestes a desistir quando achei um fórum onde um usuário teve o mesmo problema.
O problema está na biblioteca utilizada no manual (NewSoftSerial) que não funciona com o arduino Mega. A solução é simples, basta fazer as conexões Tx/Rx nas outras portas de comunicação serial do Mega (o arduino mega tem 4 portas seriais). No meu caso, fiz a conexão utilizando a Serial1 do Mega (portas 18 e 19). O código está no final deste post.
Para ler os dados da porta serial eu estou usando um script em Python (estou abandonando o Processing) que lê os valores da porta e faz o gráfico do pH x tempo. O gráfico é atualizado constantemente e enquanto atualiza o gráfico o python salva os dados em um arquivo no computador (dados.dat). Abaixo tem uma imagem da janela do programa.

Para fazer esse script em python precisei aprender sobre dois módulos do python que eu não conhecia. O primeiro foi o pyserial, que faz a comunicação entre o python e o arduino, e o segundo é o pygame, responsável pela parte gráfica. O python tem diversas ferramentas para fazer gráficos e com certeza a pior delas é o pygame. Contudo o pygame tem outras funcionalidades que no futuro serão interessantes. Eu vou melhorar este script e adicionar botões para controle do pHmetro como, iniciar, pausar, salvar etc.

Segue um vídeo do resultado final:


Os dois códigos (arduino e python) você pode baixar clicando aqui!

Últimas considerações sobre este projeto:
Um pHmetro de bancada custa em média R$560,00. Nós precisamos importar o pH-stamp, já que não tem nacional. O custo total do projeto foi:
  • Arduino Mega - US$25,00
  • pH-stamp + ponta de prova + solução de calibração - US$80,00
  • TOTAL: US$105,00 (aproximadamente 180,00 reais)
Final da história, um equipamento equivalente e com as mesmas funcionalidades, por menos de 1/3 do preço.

sábado, 3 de setembro de 2011

Projeto: Harpa Laser

O Matheus Graciano está trabalhando numa harpa laser. O funcionamento é muito simples, um laser é apontado diretamente para um LDR (resistor dependente de luz) e fica-se monitorando o sinal vindo do LDR na porta analógica. Quando o laser é interrompido, o valor lido na porta analógica muda e então sabemos que nota deve ser tocada. Abaixo segue o vídeo da primeira versão da harpa, em breve faremos uma versão melhorada.




Nesta primeira versão da harpa usamos:

  • 7 Lasers vermelho;
  • 7 LDRs;
  • 8 Resistores de 100 Ohms;
  • 1 Botão push;
  • Fios, muitos fios;
  • Algumas peças da Atto.

Esta harpa é composta por 7 "cordas" que devem ser ligadas a 7 portas analógicas. Portanto, tivemos que usar o arduino Mega que tem 16 portas analógicas. Na figura abaixo eu mostro o esquema de como ligar o LDR, o botão e o Buzzer.

Neste projeto, as portas utilizadas são diferentes da imagem acima. Portanto, se for fazer a sua harpa, verifique quais portas você utilizou. No vídeo acima, não utilizamos um buzzer e sim os auto-falantes do micro. Se quiser fazer o mesmo, basta trocar o buzzer do diagrama acima por um plug fêmea de fone de ouvido. Abaixo segue o código Arduino que foi utilizado:



////////////////////////////////////////////
// Harpa Laser
// Por Matheus Graciano
////////////////////////////////////////////

// Vetores com notas musicais
// A primeira posição é a nota normal
// A segunda é a nota sustenida
float notaA[] = {440.000, 466.164};
float notaB[] = {493.883, 523.251};
float notaC[] = {523.251, 554.365};
float notaD[] = {587.329, 622.254};
float notaE[] = {659.255, 698.456};
float notaF[] = {698.456, 739.989};
float notaG[] = {783.991, 830.609};

// Algumas variáveis
float notaAnterior = 0, notaNova = 0;
int dt = 0, t0, acidente = 0;

void setup(){
pinMode(21, INPUT); //Porta onde está ligado o botao sustenido
pinMode(7, OUTPUT); //Porta do Buzzer
}

void loop(){

//Verifica se o botao está apertado
acidente = digitalRead(21);
// Varre as portas analógicas de 0 a 7 e verifica a nova nota
if(analogRead(0)< 120) {
notaAnterior = notaC[acidente]/4;
}
if(analogRead(1)< 120) {
notaAnterior = notaD[acidente]/4;
}
if(analogRead(2)< 70) {
notaAnterior = notaE[acidente]/4;
}
if(analogRead(3)< 70) {
notaAnterior = notaF[acidente]/4;
}
if(analogRead(4)< 70) {
notaAnterior = notaG[acidente]/4;
}
if(analogRead(5)< 120) {
notaAnterior = notaA[acidente]/2;
}
if(analogRead(7)< 120) {
notaAnterior = notaB[acidente]/2;
}
//Se a nota mudar, ele para e envia a nova nota
if(notaAnterior != notaNova){
noTone(7); notaNova = notaAnterior; t0 = millis(); }
// A nota final dura 1 segundo
if(dt>1000)
{
noTone(7);
}
else{
tone(7, notaNova, 1000);
}
dt = millis()-t0;
}

Em breve postaremos a nova versão da harpa. Antes de finalizar este post, agradecemos a Atto Brinquedos (www.attobrinquedos.com.br) por nos ter doado um conjunto de peças. As peças combinam muito bem com arduino, tem auxiliado bastante nos projetos que estamos realizando.

terça-feira, 30 de agosto de 2011

Apostila do Curso de Introdução ao Arduino.

Como anunciado no post anterior sábado dia 27/08 eu dei um curso de introdução ao arduino. Ao preparar o curso eu escrevi algumas notas. No link abaixo tem o pdf dessas notas de aula.

http://dl.dropbox.com/u/16556959/curso.pdf

domingo, 21 de agosto de 2011

III Maratona de software livre de Volta Redonda

Pessoal, dia 26 e 27 de agosto o ICEx vai receber a III Maratona de Software Livre de Volta Redonda. Entre as atraçōes estão a palestra de abertura do Thadeu Penna, a minha palestra e o meu curso de Introdução ao arduino. Há muitas outras palestras e cursos. Para ver a programação e se inscrever basta acessar:
http://www.iaesmevr.org/maratona2011/

segunda-feira, 18 de julho de 2011

Projeto: Fazendo o jogo do Pong com o arduino


O jogo do Pong é o primeiro videogame com fins lucrativos. O jogo é composto de duas "raquetes" (uma para cada jogador) e o objetivo é rebater a bola, evitando o ponto do seu oponente.


A imagem acima dá uma idéia melhor de como o jogo funciona. A idéia deste projeto é utilizar dois potenciômetros ao arduino e enviar a posição angular do potenciômetro para o computador através da comunicação serial. Utilizando o processing, vamos ler a porta serial e utilizar os dados recebidos para definir a posição das raquetes. A montagem do circuito é trivial.
O código do arduino é igualmente simples. Vamos ler os valores das portas analógicas e passá-los através da comunicação serial, no seguinte formato: os dois valores dos potenciômetros separados por ";".


void setup(){
Serial.begin(9600);
}
void loop(){
Serial.print(analogRead(A0));
Serial.print(";");
Serial.println(analogRead(A2));
}

Simples assim, sem nenhum mistério. Agora só precisamos fazer o código do processing para receber e interpretar as informações. Não irei colocar muitos comentários sobre o código, se alguém tiver alguma dúvida, pode postar nos comentários que eu respondo.


// Importa a biblioteca de comunicação serial
import processing.serial.*;

Serial myPort; // Cria um objeto
float raio = 20; //Raio da bola
int X, Y; //Posição X e Y da bola
float vx=2, vy=2; // Componentes X e Y da velocidade da bola
float vx0=vx, vy0=vy; // Velocidades iniciais
int p1=0; //Pontuação do jogador 1 e 2
int p2=0;
int x1=15; // Posição X das duas "raquetes"
int x2=785;
float y1=0; // Posição Y das duas "raquetes"
float y2=0;
int tam=100; // tamanho da raquete
String[] vector;

void setup(){
size( 800, 400 ); //tamanho da janela
myPort = new Serial(this, Serial.list()[0], 9600); // Inicia a comunicação com a porta serial 0
PFont f = createFont("SansSerif", 40, true); //Define a fonte utilizada no placar
textFont(f,40);
strokeWeight( 1 ); // Largura das linhas
frameRate( 44 ); // Velocidade dos quadros
X = width / 2;
Y = (height-100) / 2;
myPort.bufferUntil('\n'); //Só inicia quando houver a primeira comunicação serial.
}


void draw(){
background( 255 ); //Define a cor de fundo
////////////////////////////////////////////////////
// Pega as informações recebidas pela porta
// serial e atribui as posições X e Y das raquetes
////////////////////////////////////////////////////
if(myPort.available()>1){
String inString= myPort.readString(); // Lê tudo que foi obtido pela porta serial
String[] teste =split(inString,"\n"); // Divide em linhas
String[] vector = split(teste[teste.length-2],";"); // pega a penúltima e separa num vetor
y1 = float(vector[0]);
y2 = float(vector[1]);
y1 = map(y1, 0, 1023, 0, height-tam-100); // renormaliza pelo tamanho útil da janela.
y2 = map(y2, 0, 1023, 0, height-tam-100);
}

fill( 0, 121, 184 );
ellipse( X, Y, raio, raio );
fill(255,0,0);
rect(x1,y1,-10,tam);
fill(0,0,255);
rect(x2,y2,10,tam);
X+=vx;
Y+=vy;
////////////////////////////////////
// Colisão com as raquetes
////////////////////////////////////
if(X < x1+raio/2 && (Y > y1 && Y < y1+tam)){
X-=vx;
vx*=-1.1;
}
if(X > x2-raio/2 && (Y > y2 && Y < y2+tam)){
X-=vx;
vx*=-1.1;
}
////////////////////////////////
//Fronteiras horizontais
////////////////////////////////
if(X > x2-raio/2 || X < x1-raio/2){
if(X > x2-raio/2){
p1++;
}
if(X < x1-raio/2){
p2++;
}
X = width / 2;
Y = (height-100) / 2;
vx0=-1*vx0;
vx=vx0;
vy=vy0;
fill( 0, 121, 184 );
ellipse( X, Y, raio, raio );
vx=vx0;
vy=vy0;
delay(2000);
}
/////////////////////////////////////////
// Fronteiras verticais
////////////////////////////////////////
if(Y > height-100-raio/2 || Y < raio/2){
Y-=vy;
vy*=-1;
}
/////////////////////////////////////////
// Placar
/////////////////////////////////////////
fill(0);
line(0,height-100,width,height-100);
text("Placar:",10,height-10);
fill(255,0,0);
text(p1, 350, height-10);
fill(0);
text("X",400,height-10);
fill(0,0,255);
text(p2, 450, height-10);
}


segunda-feira, 4 de julho de 2011

Resultado da segunda tarefa.

Bom, mais uma vez o Flávio Alvarenga fez o melhor trabalho. Quem será capaz de fazer um projeto melhor que ele hein? Abaixo segue o diagrama do Fritzing que ele fez e os dois códigos (Arduino + Processing):
Código Arduino


int V[3] = {6,5,3}; // 6, 5 e 3 escolhidas por serem saídas PWM, capazes de emular um sina analógico.
int PotRed = 0; // potenciometro que controla a cor vermelha
int PotGre = 1; // potenciometro que controla a cor verde
int PotBlu = 2; // potenciometro que controla a cor azul
int redVal = 0; //acumula o valor da luz vermelha
int greVal = 0; // acumula o valor da luz verde
int bluVal = 0; //acumula o valor da luz azul
void setup() {
for (int i=0; i<3; i++){ //declara os pinos 9, 6 e 3 como saída
pinMode(V[i], OUTPUT);
}
Serial.begin(9600);
}
void loop() {
redVal = (analogRead(PotRed)/4); // como o valor do potenciometro varia de 0 a 1023 dividindo o valor por 4 obtem-se valores entre 0 e 255* (Pois a variavel e um inteiro).
greVal = (analogRead(PotGre)/4); // Faz a leitura dos potenciometros e iguala ao acumulador da sua respectiva cor.
bluVal = (analogRead(PotBlu)/4);
redVal = map(redVal, 0, 1023, 0,255); //Ajusta o valor lido para ficar no intervalo [0,255]
gredVal = map(greVal, 0, 1023, 0,255);
bluVal = map(bluVal, 0, 1023, 0,255);
RGB(redVal,greVal,bluVal); // chama a função RGB
Serial.print("R");
Serial.println(analogRead(PotRed)/4); //importa para a porta Serial o valor lido na saida analogica 0 e atribui para a cor vermelha
Serial.print("G");
Serial.println(analogRead(PotGre)/4); //importa para a porta Serial o valor lido na saida analogica 1 e atribui para a cor verde
Serial.print("B");
Serial.println(analogRead(PotBlu)/4); //importa para a porta Serial o valor lido na saida analogica 2 e atribui para a cor azul
delay(100);
}
void RGB(int redVal,int greenVal, int blueVal){ // Transmite o valor lido pelo potenciometro para a porta PWM responsavel pelas cores red, green, blue.
analogWrite(V[0], redVal); // Escreve o valor do PWM do led vermelho
analogWrite(V[1], greenVal); // Escreve o valor do PWM do led verde
analogWrite(V[2], blueVal); // Escreve o valor do PWM do led azul
}


No código arduino ele definiu uma função chamada RGB() que define a cor do LED. Poderia ter feito uma função para mandar os dados para a porta serial.

Código Processing:



import processing.serial.*;
String buff = "";
int rval = 0, gval = 0, bval = 0;
int NEWLINE = 10;
Serial port;
void setup()
{
size(800, 800);
// Imprima uma lista no caso de a COM1 não funcionar
println("Portas seriais disponíveis:");
println(Serial.list());
//port = new Serial(this, "COM1", 9600);
// Use a primeira porta disponível
port = new Serial(this, Serial.list()[0], 9600);
}

void draw()
{
while (port.available() > 0) {
serialEvent(port.read());
}
background(rval, gval, bval);
}

void serialEvent(int serial)
{
// Se a variável "serial" não for igual ao valor de um caracter
// nova linha, inclua o valor à variável "buff". Se for igual,
// guarde o valor do buffer na variável "val".
if(serial != NEWLINE) {
buff += char(serial);
} else {
// O primeiro caractere diz-nos a qual cor se refere
char c = buff.charAt(0);
// Remova-o da string
buff = buff.substring(1);
// Descarte o retorno de carro ao final do buffer
buff = buff.substring(0, buff.length()-1);
// Converta a string para inteiro
if (c == 'R')
rval = Integer.parseInt(buff);
else if (c == 'G')
gval = Integer.parseInt(buff);
else if (c == 'B')
bval = Integer.parseInt(buff);
// Esvazie "buff"
buff = "";
}
}

quarta-feira, 29 de junho de 2011

ICExDuino no Youtube

Seguindo os nossos planos de expansão e dominação mundial abrimos um canal no youtube: http://www.youtube.com/ICExDuino
Avisem seus colegas, parentes e até seus inimigos.

Este é o nosso primeiro vídeo, o resultado da primeira tarefa. Quem fez este projeto foi o Daniel "Cayan" e o diferencial foi que ele adicionou um cronômetro ao semáforo. Logo mais vamos colocar o projeto deste semáforo no blog.