Problema ao pegar angulo de magnetometro HMC5883L

Fala pessoal.

Estou mexendo com um magnetometro HMC5883L.
Li e reli vários tutoriais consegui pegar os dados apontar para o norte, mas ele me mostra alguns dados errados.

O norte está certo, no caso me mostra em 180 graus, mas o resto, está bem esquisito.

Segue um gráfico do que estou recebendo.

O código é esse:

#define HMC5883_Address 0x1E
#define HMC5883_ModeRegisterAddress 0x02
#define HMC5883_ContinuousModeCommand (uint8_t)0x00
#define HMC5883_DataOutputXMSBAddress  0x03

int regbdata    = 0x40;
float gauss     = 2.5;

int outputData[6];
int xCompass, yCompass, zCompass, regb;

void compass_setup(){
  if(gauss == 0.88){
    regb = 0x00;
  }else if(gauss == 1.3){
    regb = 0x01;
  }else if(gauss == 1.9){
    regb = 0x02;
  }else if(gauss == 2.5){
    regb = 0x03;
  }else if(gauss == 4.0){
    regb = 0x04;
  }else if(gauss == 4.7){
    regb = 0x05;
  }else if(gauss == 5.6){
    regb = 0x06;
  }else if(gauss == 8.1){
    regb = 0x07;
  }
  
  Wire.beginTransmission(HMC5883_Address);
  Wire.write(regb);
  Wire.write(regbdata);
  Wire.endTransmission();
  delay(1000);
}

void compass_loop(){
  Wire.beginTransmission(HMC5883_Address);       //Initiate a transmission with HMC5883 (Write address).
  Wire.write(HMC5883_ModeRegisterAddress);       //Place the Mode Register Address in send-buffer.
  Wire.write(HMC5883_ContinuousModeCommand);     //Place the command for Continuous operation Mode in send-buffer.
  Wire.endTransmission();                         //Send the send-buffer to HMC5883 and end the I2C transmission.
  
  Wire.beginTransmission(HMC5883_Address);  //Initiate a transmission with HMC5883 (Write address).
  Wire.requestFrom(HMC5883_Address,6); 
  
  if(6 <= Wire.available()){ // If the number of bytes available for reading be <=6.
    for(int i=0;i<6;i++){
      outputData[i] = Wire.read();  //Store the data in outputData buffer
    }
  }
  
  xCompass = outputData[0] << 8 | outputData[1]; //Combine MSB and LSB of X Data output register
  zCompass = outputData[2] << 8 | outputData[3]; //Combine MSB and LSB of Z Data output register
  yCompass = outputData[4] << 8 | outputData[5]; //Combine MSB and LSB of Y Data output register
  
  getDegrees();
}

float getDegrees(){ 
  double angle = atan2((double)yCompass,(double)xCompass) * (180 / PI) + 180;

  Serial.print("angle: ");
  Serial.println(angle);
  
  return angle;
}

Alguém já teve algum problema desses?

Creio que você sabe que o Google, por enquanto, é seu amigo... Pesquisei por "HMC5883 arduino", entre os primeiros links veio este que é um um mix de tutorial com a library https://www.loveelectronics.co.uk/Tutorials/8/hmc5883l-tutorial-and-arduino-library, há muito o que influenciar e alterar a leitura do device, inclusive a resolução que está no seu sketch , testa com a lib acima.

fabiohbm007,

Como disse acima, li e reli muitos tutoriais, inclusive esse que você me passou, e você pode reparar que meu código é baseado na lib desse site.

Eu tirei uma parte do código pra apresentar o problema aqui no fórum, e a parte do cálculo de anglo é de outro tutorial.

Não teria postado nada em um fórum se não estivesse realmente com dúvida,faz alguns dias que leio materias, data sheets e blogs na internet e modifico o código.

Já testei com todas as resoluções possíveis que estão no setup do meu código e também todos os modos que o sensor disponibiliza (escalado e direto), mas ele insite em pegar esses valores como apresentei.

Vou testar uma solução que uma pessoa me passou na parte do fórum gringo, se funcionar posto aqui.

Se alguém tiver mais alguma sugestão, pode mandar.

sidneivl:
li e reli muitos tutoriais, inclusive esse que você me passou

Eu acredito no que disse, mas talvez esteja copiando código bugado. Eu não critico sem ter argumentos, na lib do site que te passei anteriormente, ao setar a resolução, a lib do cara te retorna se houve erro ao setar os valores…
O código que postou é muito parecido com este http://cdn.shopify.com/s/files/1/0038/9582/files/hmc5883_demo.pde encontrado nesse site http://shop.moderndevice.com/products/3-axis-compass
Analise no reference do arduino, a classe WIRE a função write http://arduino.cc/en/Reference/WireWrite,

Syntax
Wire.write(value)
Wire.write(string)
Wire.write(data, length)
Parameters
value: a value to send as a single byte
string: a string to send as a series of bytes
data: an array of data to send as bytes
length: the number of bytes to transmit

… ela aceita como parametros byte, string e array; mas no seu codigo você envia uma int, quem te garante que o WIRE não envia 0x00 e depois 0x03, já que uma int são 2 bytes!
Quem te garante que os codigos postados como exemplo são funcionais e livre de erros? mude regb e regbdata para byte, como demonstra o example do wire… Objetos/bancadas e ferramentas de aço/ferro podem criar distorções, já excluiu isso do BugList? Mantenha-nos informados…

Cara, fiquei com a pulga atras da orelha e o que eu te disse no post anterior(codigo bugado) É o seu problema…
Veja que, eu não possuo eu device, não testei nenhum codigo, mas tenho certeza que é a causa do seu problema…
1° uso de int como parametro no WIRE
2°Erro em setar o Config. Reg B:

Wire.beginTransmission(HMC5883_Address);
  Wire.write(regb); //essa não é a variavel contendo o valor do ganho? 
  Wire.write(regbdata); // não contem o indice do reg B 
  Wire.endTransmission();

Primeiro coloca-se o indice, depois o valor, você inverteu a ordem… :roll_eyes:
Alias reg B é 0x01, entao o certo é

  Wire.beginTransmission(address); //open communication with HMC5883
  Wire.send(0x01); //reg B
  Wire.send(modo); //modo ver abaixo
  Wire.endTransmission();

3° Erro valores do ganho:
Segundo o pdf na sparkfun, os bits que controlam o ganho são:
1110 0000, logo
0000 0000 0x00 - maior ganho
0010 0000 0x20 - configuração inicial
0100 0000 0x40
0110 0000 0x60
1000 0000 0x80
1010 0000 0xA0
1100 0000 0xC0
1110 0000 0xE0 - menor ganho

Esse são os valores corretos a serem preenchidos no reg B.

4° Erro na leitura dos vetores:
Você usa

Wire.beginTransmission(HMC5883_Address);  //Initiate a transmission with HMC5883 (Write address).
  Wire.requestFrom(HMC5883_Address,6); 
  
  if(6 <= Wire.available()){ // If the number of bytes available for reading be <=6.
    for(int i=0;i<6;i++){
      outputData[i] = Wire.read();  //Store the data in outputData buffer
    }
  }

enquanto o correto seria

  //Tell the HMC5883 where to begin reading data
  Wire.beginTransmission(address);
  Wire.send(0x03); //select register 3, X MSB register
  Wire.endTransmission();
 //Read data from each axis, 2 registers per axis
  Wire.requestFrom(address, 6);

Nesse link da Sparkfun tem o datasheet e um exemplo correto
http://www.sparkfun.com/tutorials/301

Então, não é isso...

Eu comecei por esse tutorial, meu magnetometro é da sparkfun, e o resultado é o mesmo.

Fiz as alterações que você explicou aqui, como está no código da sparkfun e o resultado é o mesmo.

Tem um pessoal relatando diversos erros com esse magnetometro.

Vou pegar a biblioteca de uma pessoa que disse ter tido esse mesmo problema e corrigiu esse pequeno erro.

Quando tiver pronto posto aqui.