Construindo uma bússola eletrônica com o módulo HMC5883L, anel de LEDs RGB e Arduino 1

O módulo Bússola Eletrônica HMC5883L permite determinar a direção do Norte através da medição do campo magnético da Terra. Neste post vamos ver alguns detalhes do seu funcionamento e sua interface com o Arduino e construir uma bússola eletrônica usando o módulo e um anel de LEDs RGB.

Bússola Eletrônica com Arduino (Figura 01)

Material Necessário

Conhecendo o módulo Bússola Eletrônica HMC5883L

Apesar do nome, este módulo não usa o chip HMC5883L, pois ele já foi descontinuado. No seu lugar é usado o QMC5833L, que foi desenvolvido a partir do licenciamento do HMC5883L, mas tem algumas diferenças. O princípio de funcionamento é igual nos dois chips: três sensores magnéticos medem a intensidade em três eixos (X, Y e Z). Estas medidas são convertidas em três números de 16 bits com sinal, através de um conversor analógico digital, e armazenadas em registradores internos.

A comunicação do módulo com um microcontrolador é feita através do protocolo I2C. Lembrando, esta é uma ligação a dois fios “em varal” onde cada dispositivo tem um endereço de 7 bits. No caso do QMC5833L, este endereço é 0x0D. As leituras e escritas nos registradores começam com uma operação de escrita I2C na qual é passado o número do registrador que será lido/escrito. Para simplificar, após cada leitura ou escrita o número do registrador a acessar é automaticamente incrementado, facilitando a leitura ou escrita de registradores consecutivos.

A figura abaixo mostra os registradores disponíveis e seus números. Reparar que o resultado da medição ocupa 6 registradores – um par para cada direção, com o byte menos significativo primeiro – na ordem X, Y e Z.

Módulo HMC5883L (Figura 02)

A correspondência dos eixos X, Y e Z com a posição física da placa pode ser observada através da indicação impressa no módulo HMC5883L:

Módulo HMC5883L (Figura 03)

Um problema com os módulos de bússola é que as leituras tem um valor (offset) somado a elas. Por este motivo é fundamental fazer um processo de calibração, realizando leituras à medida que o módulo é girado e calculando o offset de cada eixo a partir delas.

Obtida a intensidade do campo magnético nos três eixos, a trigonometria nos permite obter o ângulo para o Norte magnético da Terra (no nosso exemplo vamos supor que o módulo está horizontal e portanto o eixo Z pode ser ignorado). O Norte magnético está ligeiramente afastado do Norte geográfico. Isto pode ser compensado através da declinação magnética, que pode ser consultada para a sua localidade neste site.

Para economizar energia, o chip inicialmente está num modo ocioso (sem realizar medições); ele pode ser configurado para diversas taxas de leitura do sensores. No nosso exemplo vamos usar o modo contínuo.

Montagem da bússola eletrônica com o módulo HMC5883L, anel de LEDs RGB e Arduino

A figura abaixo mostra a montagem que vamos usar. Para facilitar a montagem foi soldada uma barra de pinos 90 graus ao anel de LEDs. É importante o módulo bússola HMC5883L e o anel de LEDs RGB estarem alinhados como na figura.

Bússola eletrônica com Arduino (Figura 04)

Código

A maioria das bibliotecas disponíveis trata somente o HMC5883L; por este motivo escrevi rotinas específicas para o QMC5883L.

#include <Wire.h>

// Classe simples para tratar a bússola
class Bussola {
  public:
    Bussola(void);
    bool inicia(void);
    void setDeclination (int graus , int mins, char dir);
    int leDirecao(void);
    void iniciaCal();
    void encerraCal();

  private:
    static const int ender_QMC = 0x0D; // endereço I2C do QMC5883
    static const int regCR1_QMC = 9;   // registrador de configuração
    static const int regSR_QMC = 11;   // registador set/reset
    static const int regXL_QMC = 0;    // primeiro registrador de dados
    static const int regST_QMC = 6;    // registrador de status

    // fatores de correção determinados na calibração
    int16_t xMin, yMin, xMax, yMax;
    float escX = 1.0;
    float escY = 1.0;
    int16_t offX = 0;
    int16_t offY = 0;

    // Diferença entre o Polo Magnético e o Geográfico
    float declination = 0.0;

    // Rotina para disparar leitura dos dados
    void pedeDados(int regStatus, int regDados);
};

Bussola bussola;

// Construtor
Bussola::Bussola(void) {
}

// Inicia comunicação com a bússola
bool Bussola::inicia() {
  // Confere o endereço
  Wire.beginTransmission(ender_QMC);
  if (Wire.endTransmission() != 0) {
    return false;
  }

  // Inicia o chip para modo contínuo
  Wire.beginTransmission(ender_QMC);
  Wire.write(regSR_QMC);
  Wire.write(0x01);
  Wire.endTransmission();
  Wire.beginTransmission(ender_QMC);
  Wire.write(regCR1_QMC);
  Wire.write(0x0D);
  Wire.endTransmission();

  return true;
}

// Define a declinação (correção entre o Norte magnético e o Norte geofráfico)
// ver http://www.magnetic-declination.com/
void Bussola::setDeclination (int graus , int mins, char dir) {
  declination = (graus + mins / 60.0) * PI / 180.0;
  if (dir == 'W') {
    declination = - declination;
  }
  Serial.println (declination);
}

// Le a direção da bússola em graus (0 a 360) em relação à marcação do eixo X
// Assume que a bússola esta na horizontal
int Bussola::leDirecao(void) {
  int16_t x, y, z;

  // Le a intesidade do campo magnético
  pedeDados(regST_QMC, regXL_QMC);
  x = Wire.read();          //LSB  x
  x |= Wire.read() << 8;    //MSB  x
  y = Wire.read();          //LSB y
  y |= Wire.read() << 8;    //MSB y
  z = Wire.read();          //LSB  z
  z |= Wire.read() << 8;    //MSB z

  // Registra mínimo e máximo para a calibração
  if (x < xMin) {
    xMin = x;
  }
  if (xMax < x) {
    xMax = x;
  }
  if (y < yMin) {
    yMin = y;
  }
  if (yMax < y) {
    yMax = y;
  }

  // corrige e calcula o angulo em radianos
  float xC = (x - offX) * escX;
  float yC = (y - offY) * escY;
  float angulo = atan2 (yC, xC) + declination;

  // Garante que está entre 0 e 2*PI
  if (angulo < 0) {
    angulo += 2.0 * PI;
  } else if (angulo >= 2 * PI) {
    angulo -= 2.0 * PI;
  }

  // Converte para graus
  return round ((angulo * 180.0) / PI);
}

void Bussola::pedeDados(int regStatus, int regDados) {
  // Espera ter um dado a ler
  do {
    Wire.beginTransmission(ender_QMC);
    Wire.write(regStatus);
    Wire.endTransmission();
    Wire.requestFrom(ender_QMC, 1);
  } while ((Wire.read() & 1) == 0);

  Wire.beginTransmission(ender_QMC);
  Wire.write(regDados);
  Wire.endTransmission();
  Wire.requestFrom(ender_QMC, 6);
}

// Inicia processo de calibração
void Bussola::iniciaCal() {
  xMax = yMax = -32768;
  xMin = yMin = 32767;
}

// Encerra a calibração
void Bussola::encerraCal() {
  Serial.print ("X: ");
  Serial.print (xMin);
  Serial.print (" - ");
  Serial.println (xMax);
  Serial.print ("Y: ");
  Serial.print (yMin);
  Serial.print (" - ");
  Serial.println (yMax);

  // Offset para centralizar leituras em zero
  offX = (xMax + xMin) / 2;
  offY = (yMax + yMin) / 2;

  // Escala para ter a mesma variação nos dois eixos
  int16_t varX = xMax - xMin;
  int16_t varY = yMax - yMin;
  if (varY > varX) {
    escY = 1.0;
    escX = (float) varY / varX;
  } else {
    escX = 1.0;
    escY = (float) varX / varY;
  }
}

Para controle do anel de LED vamos usar a biblioteca Adafruit NeoPixel, que você pode instalar direto do Gerenciador de Bibliotecas da IDE do Arduino:

Biblioteca Adafruit Neopixel (Figura 05)

Vamos usar o anel de LEDs para indicar a direção do Norte. Por exemplo, se o ângulo for exatamente 90 graus, vamos  acender apenas o LED 3. Se o ângulo for 115 graus, vamos acender os LEDs 3 e 4 com igual intensidade. Se o ângulo for 100 graus, os LED 3 e 4 serão acesos, porém o LED 3 será aceso mais forte.  A figura abaixo mostra a correspondência entre o índice do LED e o ângulo:

Anel de LED RGB (Figura 06)

A rotina abaixo acende os LEDs apropriados:

#include <Adafruit_NeoPixel.h>

const int PINO_ANEL = 3;
const int IMAX = 63; // Intensidade máxima, 0 a 255

Adafruit_NeoPixel anel(12, PINO_ANEL, NEO_GRB + NEO_KHZ800);

// Acende um ou dois LED do anel para indicar um ângulo
// em relação ao eixo X do sensor
// 0 <= angulo < 360
void aponta (int angulo) {
  // corrige o sentido
  angulo = 360 - angulo;
  if (angulo == 360) {
    angulo = 0;
  }
  // determina o primeiro LED
  int a = angulo / 30;
  a = (a + 10) % 12;

  // determina a intensidade do segundo LED
  int b = ((angulo % 30) * IMAX) / 30;

  // Acende os LEDs
  anel.clear();
  anel.setPixelColor (a, anel.Color(0, IMAX - b, IMAX - b));
  anel.setPixelColor ((a + 1) % 12, anel.Color(0, b, b));
  anel.show();
}

Após iniciarmos bússola e LED, vamos realizar uma calibração por 20 segundos.

// Iniciação
void setup() {
  // Inicia os LEDs
  anel.begin();
  anel.clear();

  // Inica a bussola
  Wire.begin();
  Serial.begin(115200);
  if (!bussola.inicia()) {
    Serial.println ("Nao encontrou a bussola!");
    for (;;) {
      delay(100);
    }
  }

  // Calibração da bussola
  Serial.println ("Calibrando... rode o sensor em um círculo");
  int pos = 0;
  bussola.iniciaCal();
  long tmpFim = millis() + 20000L;
  while (millis() < tmpFim) {
    bussola.leDirecao();
    aponta (pos);
    pos += 5;
    if (pos == 360) {
      pos = 0;
    }
    delay (10);
  }
  bussola.encerraCal();
  Serial.println ("Calibrado");
}

O programa principal lê a bússola e apresenta a direção do Norte nos LEDs.

// Laço principal
void loop() {
  aponta(bussola.leDirecao());
  delay (200);
}

Colocando a bússola eletrônica com Arduino para funcionar

  1. Faça a montagem do circuito conforme a figura.
  2. Execute a IDE do Arduino no seu computador.
  3. Certifique-se que a placa selecionada no menu Ferramentas é o Arduino Nano.
  4. Conecte o Nano ao computador.
  5.  Selecione no menu Ferramentas a porta onde o Nano está conectado.
  6. Copie (ou digite) o código acima (as quatro partes) em um novo sketch e salve com o nome “Bussola” (ou outro de sua preferência).
  7. Carregue o código no Arduino Nano.
  8. Após a carga (ou um reset do Arduino) os LEDs serão acesos sequencialmente de forma rápida, indicando que está sendo realizada a calibração. Gire a montagem para que o programa consiga registrar a leitura em todos os ângulos, procurando manter a protoboard paralela ao chão.
  9. Após 20 segundos a calibração será encerrada e os LEDs acesos passarão a indicar a direção do Norte magnético.

Resultado

Após a calibração, os LEDs acessos indicarão a direção do Norte magnético:

Bússola eletrônica com Arduino (Figura 7)

Conclusão

Usando o módulo Bússola Eletrônica HMC5883L podemos medir a direção para o Norte. Isto pode ser usado para fazer uma bússola (como neste projeto), descobrir a orientação do sensor ou até navegar um veículo robótico.

Agora que você já conhece o módulo Bússola Eletrônica HMC5883L e sabe como usá-lo, que tal testar algum projeto com ele?

Gostou do artigo “Construindo uma bússola eletrônica com o módulo HMC5883L, uma anel de LEDs RGB e um Arduino”? Deixe seu comentário logo abaixo dizendo o que achou. Para mais artigos e tutorias de projetos acesse nosso blog. E se quiser postar seu projeto, acesse nosso fórum.

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Um Comentário

  1. Muito bom!
    Parabens!

    Lindolff Thadeu Carneiro