25 setembro 2014

Controlando servo motor com o Motor Shield L293D

Aqui no Arduino e Cia já temos dois posts falando sobre o Motor Shield L293D :



Faltva apenas a parte de controle de servo motores para cobrirmos todas as opções do Motor Shield L293D, e é isso que vamos ver nesse post.

Motor Shield L293D e Micro Servo

Controlar servos com o Motor Shield é tarefa mais simples do que trabalhar com motores DC e motores de passo, já que temos 2 conectores, no canto superior esquerdo, específicos para ligação dos servo motores :

Arduino Motor Shield L293D - Conectores
A alimentação do servo ligado à um dos conectores é feita pelo próprio Arduino (5v), e na placa que eu tenho o Servo 1 (conector superior) é controlado pelo pino digital 10 do Arduino, e o Servo 2 (conector inferior) é controlado pelo pino 9

Observação : no site oficial do Motor Shield esta informação está invertida : Servo 1 no pino D9 e Servo 2 no pino D10. Pode ser a versão da placa ou apenas uma marcação errada. Na dúvida, teste as duas configurações.

O servo motor que eu utilizei para testar foi o Micro Servo 9G. Observe que o primeiro pino mais à esquerda é o negativo (GND), o do meio é o Vcc e o mais à direita é o pino de sinal (S).


Circuito Motor Shield e Micro Servo 9G

Ao contrário do motor DC e do motor de passo, que utilizam a biblioteca AF_Motor, com o servo motor utilizamos a própria biblioteca Servo do Arduino. 

O programa abaixo movimenta o servo entre 0 e 180 graus, e depois volta à posição inicial repetindo o processo :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// Programa : Controle de servo com Motor Shield L293D
// Autor : Arduino e Cia

// Carrega a biblioteca Servo
#include <Servo.h> 
 
// Cria um objeto chamado servo1
Servo servo1;

int val = 0;
 
void setup() 
{ 
  // Indica que o servo1 esta ligado ao pino 10
  servo1.attach(10);  
  Serial.begin(9600);
} 
 
void loop() 
{ 
  // Movimenta o servo
  servo1.write(val);  
  delay(100);
  val = val+5;
  // Envia as informacoes de val para a serial
  Serial.println(val);
  
  // Verifica se o valor de val chegou a 180
  if (val == 180)
  {
    // Caso val chegue a 180, volta a 0
    val = 0;
  }
  
  // Aguarda 15 ms e reinicia o processo
  delay(15);
} 


22 setembro 2014

Contador de visitantes usando led IR e fototransistor

O projeto do post de hoje foi usado no ano passado em um TCC, onde o aluno precisava criar um sistema que contasse o número de visitantes em uma sala, utilizando led infravermelho e fototransistor.

O sistema deveria contar o número de pessoas que entraram na sala, quantas saíram, calcular o número de pessoas na sala e, caso não houvesse ninguém, apagar a luz.

contador de visitantes ir fototransistor


Essas informações deveriam ser apresentadas em um display LCD 16x2, e com a utilização do Arduino a parte eletrônica ficou bem reduzida, facilitando a instalação do projeto em uma maquete.

No projeto, mostrado na foto acima, foram utilizados os seguintes componentes:

  • 1 led comum (para simular a luz da sala)
  • 2 leds IR 5mm
  • 2 fototransistores 5mm
  • 1 resistor de 220R para o led comum
  • 2 resistores de 220R para os leds IR
  • 2 resistores de 220R para o coletor do fototransistor
  • 2 resistores de 330R para o emissor do fototransistor
  • 1 display LCD 16x2 HD44780
  • 1 potenciômetro de 10 K

O esquema de ligação do display é o mesmo que eu utilizei na maioria dos projetos aqui no site (clique aqui para ver outros posts sobre display LCD aqui no Arduino e Cia). Na porta 7 ligamos o fototransistor que será responsável pela contagem de entrada da sala, e na porta 6 o responsável pela contagem de saída. O led que simula a luz da sala está ligado à porta 10 :


IR fototransistor


No circuito acima, cada fototransistor (em azul) tem a perna mais curta (o coletor) ligada ao positivo junto com um resistor de 220R, e a perna mais comprida (o emissor) ligada à porta do Arduino, com um resistor de 330R fazendo a função de pull-down. O potenciômetro ajusta o contraste do display.

O programa verifica o estado das portas 7 (sensor de entrada da sala) e 6 (sensor de saída da sala), que se encontram em nível alto enquanto estiverem recebendo iluminação dos leds IR (que estão sempre ligados). Quando a iluminação IR é interrompida por algum objeto, o estado da porta vai à nível baixo (0 / LOW), e o contador é então atualizado.

Na parte superior do display, mostramos a quantidade de pessoas na sala, e o total de visitantes. Na parte inferior do display, temos o contador de entrada e de saída, apenas para informação e acompanhamento.


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Programa : Controle de visitantes
// Autor : Arduino e Cia

// Pino de ligacao do sensor IR de entrada
int pinoirent = 7;    
// Pino de ligacao do sensor IR de saida
int pinoirsaida = 6;  
// Variavel que registra o estado do sensor de entrada
int valorirent = 0;   
// Variavel que registra o estado do sensor de saida
int valorirsai = 0;   
// Variavel que registra a quantidade de visitantes que entraram
int content = 0;      
// Variavel que registra a quantidade de visitantes que sairam
int contsai = 0;      
// Variavel que registra a quantidade de pessoas na sala
int contsala = 0;     
// Variavel que registra a quantidade anterior de pessoas na sala
int contanterior = 0; 
// Pino de ligacao do led que representa a luz da sala
int pinoledsala = 10; 


// Configuracao do display LCD
#include <LiquidCrystal.h> 
LiquidCrystal lcd(12, 11, 5, 4, 3, 2); 
 

void setup()
{
  Serial.begin(9600);            
  // Seta o pino do sensor de entrada como ENTRADA
  pinMode(pinoirent, INPUT);     
  // Seta o pino do sensor de saida como ENTRADA
  pinMode(pinoirsaida, INPUT);   
  // Seta o pino do Led indicador de presenca como SAIDA
  pinMode(pinoledsala, OUTPUT);  
  // Informacoes iniciais do display
  lcd.begin(16, 2);
  lcd.setCursor(0,0);            
  lcd.print("Sala:0 ");          
  lcd.setCursor(9,0);
  lcd.print("Tot: 0");
  lcd.setCursor(0,1);
  lcd.print("Ent: 0");
  lcd.setCursor(9,1);
  lcd.print("Sai: 0");
}

void loop()
{
  // Seta a variavel valorirent com o status do sensor de entrada
  valorirent = digitalRead(pinoirent);    
  // Seta a variavel valorirsai com o status do sensor de saida
  valorirsai = digitalRead(pinoirsaida);  

  // Mostra as informacoes dos sensores no serial monitor
  Serial.print("entrada : ");
  Serial.print(valorirent);
  Serial.print(" saida : ");
  Serial.println(valorirsai);

  // Verifica se o estado do sensor de entrada foi alterado
  if(valorirent!=1) 
  {
    // Incrementa o valor do contador de entrada em 1 unidade
    content=content+1; 
    // Verifica se a pessoa/objeto para em frente ao sensor
    while(digitalRead(pinoirent)!=1) 
      { 
        delay(100);  
        Serial.println("Sensor de entrada parado !");
      }
    // Atualiza no LCD o valor do contador de entrada
    lcd.setCursor(5,1); 
    lcd.print(content); 
    // Atualiza no LCD o valor total de visitantes
    lcd.setCursor(14,0); 
    lcd.print(content); 
  }

  // Verifica se o estado do sensor de saida foi alterado
  if(valorirsai!=1) 
  {
    // Incrementa o valor do contador de saida em 1 unidade
    contsai=contsai+1; 
    // Verifica se a pessoa/objeto para em frente ao sensor
    while(digitalRead(pinoirsaida)!=1)
      { 
       delay(100); 
       Serial.println("Sensor de saida parado !");
      }
    // Atualiza no LCD o valor do contador de saida
    lcd.setCursor(14,1);
    lcd.print(contsai);   
  }

  // Calcula o numero de visitantes na sala
  contsala=content-contsai; 
  // Verifica se o numero atual de visitantes na sala foi alterado.
  if (contsala != contanterior)
  {
    lcd.setCursor(5,0); 
    // Imprime 2 posicoes em branco, para limpar o cursor na 
    // coluna 5, linha 0
    lcd.print("  "); 
    lcd.setCursor(5,0);
    // Atualiza no LCD o numero de visitantes na sala
    lcd.print(contsala); 
    // Apos atualizar no LCD, coloca na varivel CONTANTERIOR 
    // o valor atual de visitantes na sala (CONTASALA} 
    contanterior = contsala; 

    // Verifica se o valor do contador de pessoas na sala 
    // e maior do que 0
    if (contsala > 0) 
    {
      //Caso positivo, acende a luz/led
      digitalWrite(pinoledsala,1); 
    }
      else
    { 
      //Caso negativo, apaga a luz/led
      digitalWrite(pinoledsala,0); 
    } 
  }
}

Também para fins de acompanhamento, os valores dos sensores são mostrados no serial monitor. Caso alguma pessoa ou objeto pare em frente ao sensor, essa informação também é mostrada :

Serial Monitor - Dados IR

O funcionamento desse projeto você confere no vídeo abaixo :



18 setembro 2014

Como programar o Arduino Pro Mini usando conversor FTDI

Quem mexe com Arduino ou com outros microcontroladores já deve ter ouvido falar no conversor FTDI, um conversor USB para serial que permite a comunicação entre o computador e outros equipamentos eletrônicos que possuam porta de comunicação no padrão TTL.

Conversor USB-TTL serial FTDI232

FTDI são as iniciais de Future Technology Devices International (www.ftdichip.com), uma empresa especializada em tecnologia USB e que é a fabricante do chip FT232RL (datasheet), cérebro da placa mostrada na imagem acima.

No Arduino esse conversor é muito utilizado para programar placas que não possuem a comunicação USB-Serial embutida, como é o caso do Arduino Pro Mini, mostrado abaixo.

Arduino Pro Mini

O Arduino Pro Mini é uma placa ideal para projetos compactos, com microcontrolador ATmega328p, 14 portas digitais, 8 analógicas, clock de 16 Mhz e memória de 32K. A programação dessa placa pode ser feita pelo Arduino Uno, utilizando os pinos laterais GRN, TX, RX, Vcc, GND e BLK do Pro Mini.

Veja também como utilizar o conversor FTDI para programar o Lilypad no artigo Lilypad - O Arduino que você pode costurar na sua roupa.

Mas isso dá, digamos assim, um certo trabalho, e é aí que entra o conversor FTDI232 que mostramos no início do post. Basta ligar o conversor ao Arduino na sequência mostrada abaixo. Ele também possui um jumper para selecionar o nível de sinal (5v ou 3.3V),  leds indicadores de atividade na recepção e transmissão (RX/TX),e também um led que indica se o módulo está ligado :

Ligação conversor FTDI - Arduino Pro Mini



Ao conectar o conversor FTDI ao computador, a instalação no Windows foi feita automaticamente, com dois dispositivos detectados : USB Serial Converter, e USB Serial Port :


Conversor FTDI232 - Drivers


É essa porta (no nosso caso, a COM21) que vamos utilizar para fazer a comunicação com o Arduino Pro Mini, selecionando a placa Arduino Pro or Pro Mini (5v, 16 MHz) w/ ATmega328 em Ferramentas => Placa e a porta COM21 em Ferramentas => Porta Serial :


Configuração IDE - Arduino Pro Mini

































Com essas pequenas configurações , basta agora transferir normalmente os programas para o Arduino Pro Mini, do mesmo jeito que você faria com um Uno ou Mega, por exemplo.

Lembrando que esse conversor FTDI pode ser utilizado também quando montamos o Arduino na protoboard, assim teremos uma configuração completa com o ATmega e o conversor USB-Serial, o que facilita muito a gravação dos programas no microcontrolador.



08 setembro 2014

Sensor GY-80 - Acelerômetro Giroscópio Magnetômetro e Barômetro

Quatro sensores em uma mesma placa : acelerômetro, giroscópio, magnetômetro e barômetro. Esse é o sensor GY-80, um multi-sensor conhecido como IMU (Inertial Measurement Unit), que reúne numa mesma placa vários dispositivos de medição.

GY-80 acelerometro giroscopio magnetometro barometro

As funções dessa placa são controladas por 4 CIs, cada um com sua função específica :

  • L3G4200D (3-Axis Angular Rate Sensor) - Giroscópio 3 eixos
  • ADXL345 (3-Axis Digital Accelerometer) - Acelerômetro 3 eixos
  • HMC5883L (3-Axis Digital Compass) - Bússola digital / Magnetômetro
  • BMP085 (Barometric Pressure Sensor) - Sensor de temperatura e pressão

A comunicação com o Arduino é feita pela interface I2C, e todos os sensores citados acima são endereçados individualmente. A ligação básica ao Arduino utiliza somente 4 pinos, dos 10 disponíveis no módulo. Observe que você pode alimentar o módulo tanto com 5v como com 3.3v :

GY-80 Pinagem

  • VCC_IN - Utilize este pino para alimentar o sensor com 5v
  • VCC_3.3V - Utilize este pino para alimentar o sensor com 3.3v
  • GND - Conectado ao GND do Arduino
  • SCL - Conectado ao pino analógico A5 do Arduino Uno (ou pino 21 do Arduino Mega)
  • SDA - Conectado ao pino analógico A4 do Arduino Uno (ou pino 20 do Arduino Mega)

Conectando o GY-80 ao Arduino

Vamos mostrar como utilizar separadamente cada sensor ligando-o ao Arduino Uno . Como todos eles utilizam o mesmo barramento I2C, teremos apenas um circuito para todos os programas exemplo : 

Circuito GY-80 e Arduino Uno R3
 
A primeira coisa que você vai notar é que ao alimentar o módulo não há nenhuma indicação de que ele está ligado. A placa não possui nenhum led , logo vamos utilizar um programa chamado I2C Scanner (http://playground.arduino.cc/Main/I2cScanner) para efetuar um rastreamento no barramento I2C e garantir que o módulo esteja adequadamente ligado ao Arduino. Carregue o I2C Scanner :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
// --------------------------------------
// i2c_scanner
//
// Version 1
//    This program (or code that looks like it)
//    can be found in many places.
//    For example on the Arduino.cc forum.
//    The original author is not know.
// Version 2, Juni 2012, Using Arduino 1.0.1
//     Adapted to be as simple as possible by Arduino.cc user Krodal
// Version 3, Feb 26  2013
//    V3 by louarnold
// Version 4, March 3, 2013, Using Arduino 1.0.3
//    by Arduino.cc user Krodal.
//    Changes by louarnold removed.
//    Scanning addresses changed from 0...127 to 1...119,
//    according to the i2c scanner by Nick Gammon
//    http://www.gammon.com.au/forum/?id=10896
// Version 5, March 28, 2013
//    As version 4, but address scans now to 127.
//    A sensor seems to use address 120.
// 
//
// This sketch tests the standard 7-bit addresses
// Devices with higher bit address might not be seen properly.
//

#include <Wire.h>


void setup()
{
  Wire.begin();

  Serial.begin(9600);
  Serial.println("\nI2C Scanner");
}


void loop()
{
  byte error, address;
  int nDevices;

  Serial.println("Scanning...");

  nDevices = 0;
  for(address = 1; address < 127; address++ ) 
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");

      nDevices++;
    }
    else if (error==4) 
    {
      Serial.print("Unknow error at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");

  delay(5000);           // wait 5 seconds for next scan
}

Se as conexões estiverem corretas, ao abrir o serial monitor você terá a seguinte tela, mostrando os endereços dos dispositivos detectados :

I2C Scanner - Serial Monitor

O I2C Scanner é um programa que serve não apenas para este módulo, mas também para qualquer outro dispositivo I2C conectado ao barramento.  Tenha este programa sempre à mão para descobrir o endereço do dispositivo ou simplesmente para verificar se ele está se comunicando com o Arduino.

L3G4200D - Giroscópio 3 eixos

O primeiro programa é para o L3G4200D (datasheet), ou seja, o Giroscópio de 3 eixos do GY-80, cujo endereço I2C é 0x69 (ou 150 em decimal). Carregue o seguinte programa no Arduino :

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// Programa : Teste Giroscopio L3G4200D
// Adaptacoes : Arduino e Cia

#include <Wire.h>

#define CTRL_REG1 0x20
#define CTRL_REG2 0x21
#define CTRL_REG3 0x22
#define CTRL_REG4 0x23
#define CTRL_REG5 0x24

//Endereco I2C do L3G4200D
int L3G4200D_Address = 105;

int x;
int y;
int z;

void setup()
{
  Wire.begin();
  Serial.begin(9600);

  Serial.println("Inicializando o L3G4200D");
  // Configura o L3G4200 para 200, 500 ou 2000 graus/seg
  setupL3G4200D(2000); 

  // Aguarda a resposta do sensor
  delay(1500); 
}

void loop()
{
  // Atualiza os valores de X, Y e Z
  getGyroValues();  

  // Mostra os valores no serial monitor
  Serial.print("X:");
  Serial.print(x);

  Serial.print(" Y:");
  Serial.print(y);

  Serial.print(" Z:");
  Serial.println(z);

  // Aguarda 100ms e reinicia o processo
  delay(100);
}

void getGyroValues()
{
  // Rotina para leitura dos valores de X, Y e Z
  byte xMSB = readRegister(L3G4200D_Address, 0x29);
  byte xLSB = readRegister(L3G4200D_Address, 0x28);
  x = ((xMSB << 8) | xLSB);

  byte yMSB = readRegister(L3G4200D_Address, 0x2B);
  byte yLSB = readRegister(L3G4200D_Address, 0x2A);
  y = ((yMSB << 8) | yLSB);

  byte zMSB = readRegister(L3G4200D_Address, 0x2D);
  byte zLSB = readRegister(L3G4200D_Address, 0x2C);
  z = ((zMSB << 8) | zLSB);
}

int setupL3G4200D(int scale)
{
  //From  Jim Lindblom of Sparkfun's code

  // Enable x, y, z and turn off power down:
  writeRegister(L3G4200D_Address, CTRL_REG1, 0b00001111);

  // If you'd like to adjust/use the HPF, you can edit the line below to configure CTRL_REG2:
  writeRegister(L3G4200D_Address, CTRL_REG2, 0b00000000);

  // Configure CTRL_REG3 to generate data ready interrupt on INT2
  // No interrupts used on INT1, if you'd like to configure INT1
  // or INT2 otherwise, consult the datasheet:
  writeRegister(L3G4200D_Address, CTRL_REG3, 0b00001000);

  // CTRL_REG4 controls the full-scale range, among other things:
  if(scale == 250){
    writeRegister(L3G4200D_Address, CTRL_REG4, 0b00000000);
  }else if(scale == 500){
    writeRegister(L3G4200D_Address, CTRL_REG4, 0b00010000);
  }else{
    writeRegister(L3G4200D_Address, CTRL_REG4, 0b00110000);
  }

  // CTRL_REG5 controls high-pass filtering of outputs, use it
  // if you'd like:
  writeRegister(L3G4200D_Address, CTRL_REG5, 0b00000000);
}

void writeRegister(int deviceAddress, byte address, byte val) 
{
    Wire.beginTransmission(deviceAddress); // start transmission to device 
    Wire.write(address);       // send register address
    Wire.write(val);         // send value to write
    Wire.endTransmission();     // end transmission
}

int readRegister(int deviceAddress, byte address)
{
    int v;
    Wire.beginTransmission(deviceAddress);
    Wire.write(address); // register to read
    Wire.endTransmission();

    Wire.requestFrom(deviceAddress, 1); // read a byte

    while(!Wire.available()) 
    {
        // waiting
    }
    v = Wire.read();
    return v;
}

Abra o serial monitor para verificar a velocidade angular dos eixos X, Y e Z (em graus/s). Os valores são atualizados a cada 100ms :

Dados L3G4200D - Serial Monitor


ADXL345 - Acelerômetro 3 eixos

O acelerômetro é muito popular hoje em dia graças à sua utilização nos telefones celulares. É através do acelerômetro que o seu celular detecta a posição do aparelho e permite que você passe horas naquele joguinho de corrida sem apertar nenhum botão, apenas movimentando o aparelho. :)

Utilize o programa abaixo para testar o ADXL345 (datasheet), cujo endereço I2C é 0x53 (ou 83 em decimal) :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
// Programa : Teste acelerometro ADXL345
// Adaptacoes : Arduino e Cia

#include <Wire.h>

#define Register_ID 0
#define Register_2D 0x2D
#define Register_X0 0x32
#define Register_X1 0x33
#define Register_Y0 0x34
#define Register_Y1 0x35
#define Register_Z0 0x36
#define Register_Z1 0x37

// Endereco I2C do sensor : 83 em decimal ou 0x53
int ADXAddress = 0x53;  // the default 7-bit slave address
int reading = 0;
int val=0;
int X0,X1,X_out;
int Y0,Y1,Y_out;
int Z1,Z0,Z_out;
double Xg,Yg,Zg;

void setup()
{
  Wire.begin();                
  Serial.begin(9600);    
  delay(100);
  // enable to measute g data
  Wire.beginTransmission(ADXAddress);
  Wire.write(Register_2D);
  Wire.write(8);                //measuring enable
  Wire.endTransmission();     // stop transmitting
}

void loop()
{
  //--------------X
  Wire.beginTransmission(ADXAddress); // transmit to device
  Wire.write(Register_X0);
  Wire.write(Register_X1);
  Wire.endTransmission();
  Wire.requestFrom(ADXAddress,2); 
  if(Wire.available()<=2)   
  {
    X0 = Wire.read();
    X1 = Wire.read(); 
    X1=X1<<8;
    X_out=X0+X1;   
  }

  //------------------Y
  Wire.beginTransmission(ADXAddress); // transmit to device
  Wire.write(Register_Y0);
  Wire.write(Register_Y1);
  Wire.endTransmission();
  Wire.requestFrom(ADXAddress,2); 
  if(Wire.available()<=2)   
  {
    Y0 = Wire.read();
    Y1 = Wire.read(); 
    Y1=Y1<<8;
    Y_out=Y0+Y1;
  }
  //------------------Z
  Wire.beginTransmission(ADXAddress); // transmit to device
  Wire.write(Register_Z0);
  Wire.write(Register_Z1);
  Wire.endTransmission();
  Wire.requestFrom(ADXAddress,2); 
  if(Wire.available()<=2)   
  {
    Z0 = Wire.read();
    Z1 = Wire.read(); 
    Z1=Z1<<8;
    Z_out=Z0+Z1;
  }
  //
  Xg=X_out/256.0;
  Yg=Y_out/256.0;
  Zg=Z_out/256.0;
  Serial.print("X= ");
  Serial.print(Xg);
  Serial.print("       ");
  Serial.print("Y= ");
  Serial.print(Yg);
  Serial.print("       ");
  Serial.print("Z= ");
  Serial.print(Zg);
  Serial.println("  ");
  delay(200);
}

Movimente o sensor e observe a variação dos eixos X, Y e Z no serial monitor :

Dados ADXL345 - Serial Monitor


HMC5883L - Bússola digital

O HMC5883L (datasheet) é o nosso magnetômetro de 3 eixos, um instrumento usado para mediar a intensidade, direção e sentido de campos magnéticos. É com ele que podemos montar uma bússola com o Arduino, utilizando como base o programa abaixo, que mostra os valores correspondentes aos eixos X, Y e Z. O endereço I2C do sensor é 0x1E (30 em decimal) :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// Programa : Teste HMC5883L - Bussola
// Adaptacoes : Arduino e Cia

#include <Wire.h>

// Define o endereco do HMC5883 - 0x1E ou 30 em decimal
#define address 0x1E 

void setup()
{
  Serial.begin(9600);
  Wire.begin();
  
  // Inicializa o HMC5883
  Wire.beginTransmission(address);
  // Seleciona o modo
  Wire.write(0x02); 
  // Modo de medicao continuo
  Wire.write(0x00); 
  Wire.endTransmission();
}

void loop()
{
  int x,y,z; //triple axis data
  
  // Indica ao HMC5883 para iniciar a leitura
  Wire.beginTransmission(address);
  Wire.write(0x03); //select register 3, X MSB register
  Wire.endTransmission();
 
  // Le os dados de cada eixo, 2 registradores por eixo
  Wire.requestFrom(address, 6);
  if(6<=Wire.available())
  {
    x = Wire.read()<<8; //X msb
    x |= Wire.read(); //X lsb
    z = Wire.read()<<8; //Z msb
    z |= Wire.read(); //Z lsb
    y = Wire.read()<<8; //Y msb
    y |= Wire.read(); //Y lsb
  }
  
  // Imprime os vaores no serial monitor
  Serial.print("x: ");
  Serial.print(x);
  Serial.print("  y: ");
  Serial.print(y);
  Serial.print("  z: ");
  Serial.println(z);
  
  delay(250);
}

Da mesma forma que o acelerometro e o giroscópio, os valores são mostrados no serial :

Dados HMC5883L - Serial Monitor


BMP085 - Sensor de temperatura e pressão

O último sensor é o BMP085 (datasheet), do qual já falamos nesse artigo aqui no Arduino e Cia. Com ele podemos obter os valores da temperatura ambiente e da pressão, entre outras informações:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
// Programa : Teste BMP085 - Barometro / temperatura
// Adaptacoes : Arduino e Cia

/*Based largely on code by  Jim Lindblom
 Get pressure, altitude, and temperature from the BMP085.
 Serial.print it out at 9600 baud to serial monitor.
*/

#include <Wire.h>

//Define o endereco I2C do BMP085 - 0x77 ou 119 em decimal
#define BMP085_ADDRESS 0x77  

const unsigned char OSS = 0;  // Oversampling Setting

// Calibration values
int ac1;
int ac2;
int ac3;
unsigned int ac4;
unsigned int ac5;
unsigned int ac6;
int b1;
int b2;
int mb;
int mc;
int md;

// b5 is calculated in bmp085GetTemperature(...), this 
// variable is also used in bmp085GetPressure(...)
// so ...Temperature(...) must be called before ...Pressure(...).
long b5; 

void setup()
{
  Serial.begin(9600);
  Wire.begin();
  // Inicializa o BMP085
  bmp085Calibration();
}

void loop()
{
  // Chama a rotina que calcula a temperatura
  // Esta rotina DEVE ser executada primeiro
  float temperature = bmp085GetTemperature(bmp085ReadUT());
  // Chama a rotina que calcula a pressao
  float pressure = bmp085GetPressure(bmp085ReadUP());
  // Chama a rotina que calcula atmosfera
  float atm = pressure / 101325; 
  // Chama a rotina que calcula a altitude
  float altitude = calcAltitude(pressure); 

  Serial.print("Temperatura: ");
  // Mostra a temperatura com 2 casas decimais
  Serial.print(temperature, 2); 
  Serial.println(" C");

  Serial.print("Pressao: ");
  Serial.print(pressure, 0); 
  Serial.println(" Pa");

  Serial.print("Atmosfera padrao : ");
  // Mostra o valor com 4 casas decimais
  Serial.println(atm, 4); //display 4 decimal places

  Serial.print("Altitude: ");
  // Mostra o valor com 2 casas decimais
  Serial.print(altitude, 2); 
  Serial.println(" M");

  Serial.println();

  //Aguarda 5 segundos e reinicia o processo
  delay(5000);
}

// Armazena todos os valores de calibracao do BMP085 em 
// variaveis globais. Valores de calibracao sao exigidos para
// calcular temperatura e pressao
// Esta funcao deve ser chamada/acionada no inicio do programa
void bmp085Calibration()
{
  ac1 = bmp085ReadInt(0xAA);
  ac2 = bmp085ReadInt(0xAC);
  ac3 = bmp085ReadInt(0xAE);
  ac4 = bmp085ReadInt(0xB0);
  ac5 = bmp085ReadInt(0xB2);
  ac6 = bmp085ReadInt(0xB4);
  b1 = bmp085ReadInt(0xB6);
  b2 = bmp085ReadInt(0xB8);
  mb = bmp085ReadInt(0xBA);
  mc = bmp085ReadInt(0xBC);
  md = bmp085ReadInt(0xBE);
}

// Calcula a temperatura em graus C
float bmp085GetTemperature(unsigned int ut)
{
  long x1, x2;

  x1 = (((long)ut - (long)ac6)*(long)ac5) >> 15;
  x2 = ((long)mc << 11)/(x1 + md);
  b5 = x1 + x2;

  float temp = ((b5 + 8)>>4);
  temp = temp /10;

  return temp;
}

// Calcula a pressao. Os valores de calibracao devem ser conhecidos
// b5 tambem eh exigido, logo a funcao bmp085GetTemperature(...) deve
// ser executada primeiro.
// Funcao retorna pressao em unidades de Pa
long bmp085GetPressure(unsigned long up){
  long x1, x2, x3, b3, b6, p;
  unsigned long b4, b7;

  b6 = b5 - 4000;
  // Calcula B3
  x1 = (b2 * (b6 * b6)>>12)>>11;
  x2 = (ac2 * b6)>>11;
  x3 = x1 + x2;
  b3 = (((((long)ac1)*4 + x3)<<OSS) + 2)>>2;

  // Calcula B4
  x1 = (ac3 * b6)>>13;
  x2 = (b1 * ((b6 * b6)>>12))>>16;
  x3 = ((x1 + x2) + 2)>>2;
  b4 = (ac4 * (unsigned long)(x3 + 32768))>>15;

  b7 = ((unsigned long)(up - b3) * (50000>>OSS));
  if (b7 < 0x80000000)
    p = (b7<<1)/b4;
  else
    p = (b7/b4)<<1;

  x1 = (p>>8) * (p>>8);
  x1 = (x1 * 3038)>>16;
  x2 = (-7357 * p)>>16;
  p += (x1 + x2 + 3791)>>4;

  long temp = p;
  return temp;
}

// Read 1 byte from the BMP085 at 'address'
char bmp085Read(unsigned char address)
{
  unsigned char data;

  Wire.beginTransmission(BMP085_ADDRESS);
  Wire.write(address);
  Wire.endTransmission();

  Wire.requestFrom(BMP085_ADDRESS, 1);
  while(!Wire.available())
    ;

  return Wire.read();
}

// Read 2 bytes from the BMP085
// First byte will be from 'address'
// Second byte will be from 'address'+1
int bmp085ReadInt(unsigned char address)
{
  unsigned char msb, lsb;

  Wire.beginTransmission(BMP085_ADDRESS);
  Wire.write(address);
  Wire.endTransmission();

  Wire.requestFrom(BMP085_ADDRESS, 2);
  while(Wire.available()<2)
    ;
  msb = Wire.read();
  lsb = Wire.read();

  return (int) msb<<8 | lsb;
}

// Read the uncompensated temperature value
unsigned int bmp085ReadUT(){
  unsigned int ut;

  // Write 0x2E into Register 0xF4
  // This requests a temperature reading
  Wire.beginTransmission(BMP085_ADDRESS);
  Wire.write(0xF4);
  Wire.write(0x2E);
  Wire.endTransmission();

  // Wait at least 4.5ms
  delay(5);

  // Read two bytes from registers 0xF6 and 0xF7
  ut = bmp085ReadInt(0xF6);
  return ut;
}

// Read the uncompensated pressure value
unsigned long bmp085ReadUP(){

  unsigned char msb, lsb, xlsb;
  unsigned long up = 0;

  // Write 0x34+(OSS<<6) into register 0xF4
  // Request a pressure reading w/ oversampling setting
  Wire.beginTransmission(BMP085_ADDRESS);
  Wire.write(0xF4);
  Wire.write(0x34 + (OSS<<6));
  Wire.endTransmission();

  // Wait for conversion, delay time dependent on OSS
  delay(2 + (3<<OSS));

  // Read register 0xF6 (MSB), 0xF7 (LSB), and 0xF8 (XLSB)
  msb = bmp085Read(0xF6);
  lsb = bmp085Read(0xF7);
  xlsb = bmp085Read(0xF8);

  up = (((unsigned long) msb << 16) | ((unsigned long) lsb << 8) | (unsigned long) xlsb) >> (8-OSS);

  return up;
}

void writeRegister(int deviceAddress, byte address, byte val) {
  Wire.beginTransmission(deviceAddress); // start transmission to device 
  Wire.write(address);       // send register address
  Wire.write(val);         // send value to write
  Wire.endTransmission();     // end transmission
}

int readRegister(int deviceAddress, byte address){

  int v;
  Wire.beginTransmission(deviceAddress);
  Wire.write(address); // register to read
  Wire.endTransmission();

  Wire.requestFrom(deviceAddress, 1); // read a byte

  while(!Wire.available()) {
    // waiting
  }

  v = Wire.read();
  return v;
}

float calcAltitude(float pressure)
{
  float A = pressure/101325;
  float B = 1/5.25588;
  float C = pow(A,B);
  C = 1 - C;
  C = C /0.0000225577;

  return C;
}

No serial monitor, as informações são atualizadas a cada 5 segundos :

Dados BMP085 - Serial Monitor

 
Um bom exercício é utilizar esses programas e realizar a integração com o Processing (veja o post Processing : mostre as informações do Arduino no seu computador), mostrando as informações do sensor de forma gráfica ou até mesmo por meio de animações.


02 setembro 2014

Processing : mostre as informações do Arduino no seu computador

Hoje vamos ver como mostrar informações do Arduino na tela do computador utilizando o Processing, uma linguagem de programação de código aberto usada para escrever programas utilizando representação gráfica. Com ela você consegue criar imagens e animações e por esse motivo é uma linguagem muito utilizada por profissionais de design e ilustradores.

No Arduino, podemos utilizar o Processing para coletar as informações da placa e mostrá-las na tela do computador, como fiz ligando ao Arduino um botão tipo push-button e um led.

Tutorial Arduino Processing


A parte superior da tela temos o Estado Botão, onde um círculo mostra se o led está apagado (círculo em preto), ou aceso (círculo em vermelho). No meio da tela, um contador incrementado a cada acionamento do botão, e na parte inferior um gráfico que vai sendo atualizado conforme acionamos o circuito.