LusoRobótica - Robótica em Português

Robótica => Discussão geral sobre robótica => Tópico iniciado por: Dave em 25 de Junho de 2014, 14:26

Título: LSM303DLHC - os problemas de uma "primeira vez" - acelerometro
Enviado por: Dave em 25 de Junho de 2014, 14:26
Olás.

Estou aqui com um pequeno problema de entendimento com o acelerometro.

Muito provavelmente não devo ter começado com o melhor dos integrados para uma "primeira vez"... mas "a cavalo dado...".

Na internet o geral dos problemas que vejo é malta que não consegue ligar o módulo ou que está com problemas na comunicação, etc...
No meu caso, esta parte foi ultrapassada e deixo em baixo uns pequenos excertos do código.

A comunicação foi ultrapassada, a inicialização também e a leitura dos registos com os dados também.
O meu problema (e parece que mais ninguém tem esse problema porque não encontro muita informação sobre isso) é o que fazer com os valores que recebo, até chegar à aceleração em m/s^2.

Estou a tentar fazer trabalhar um eixo apenas (neste caso o X) e quando lhe mexo há alteração dos valores recebidos.

As curiosidades são:
* só tenho variação dos valores quando empurro na direcção do eixo e não ao contrário.
* essa variação faz-se quase sempre pela alteração de 2 valores, ou seja, recebo 2 bytes (High and Low) com 192 e quando empurro recebo 2 bytes a 0.
(https://lusorobotica.com/proxy.php?request=http%3A%2F%2Fi473.photobucket.com%2Falbums%2Frr100%2Fdaviddmmartins%2FCapture_zps019813d4.png&hash=13138f67501be78d3522e14c223ef7bac25246bc)
* segundo o datasheet, "X-axis acceleration data. The value is expressed in 2’s complement.", mas não vi nenhum exemplo de código onde realmente tenham feito o complemento do valor recebido.

A pergunta é, quais os passos a seguir para conseguir obter um valor válido de aceleração?

O código em baixo não está muito aprimorado, pois foi feito só mesmo para tentar obter alguns valores de teste.

Alguns #defines
Código: [Seleccione]
#define write_LSM303_MAG    0x3C 
#define write_LSM303_ACC    0x32
#define read_LSM303_MAG     0x3D 
#define read_LSM303_ACC     0x33

/* Registers */
#define CTRL_REG1_A     0x20
#define CTRL_REG4_A     0x23
#define CRA_REG_M       0x00      //temperatura e rate data out
#define CRB_REG_M       0x01
#define MR_REG_M        0x02
#define OUT_X_H_M       0x03
#define OUT_X_L_A       0x28
#define TEMP_OUT_H_M    0x31

Inicialização do LSM303
Código: [Seleccione]
void init_LSM303(void)
{
    Start_I2C();
    Write_I2C(write_LSM303_ACC);
    Write_I2C(CTRL_REG1_A);
    Write_I2C(0x27);
    Stop_I2C();

    Start_I2C();
    Write_I2C(write_LSM303_ACC);
    Write_I2C(CTRL_REG4_A);
    Write_I2C(0x40);
    Stop_I2C();

    Start_I2C();
    Write_I2C(write_LSM303_MAG);
    Write_I2C(CRA_REG_M);
    Write_I2C(0x14);
    Stop_I2C();

   
    Start_I2C();
    Write_I2C(write_LSM303_MAG);
    Write_I2C(CRB_REG_M);
    Write_I2C(0b01100000);
    Stop_I2C();

    Start_I2C();
    Write_I2C(write_LSM303_MAG);
    Write_I2C(MR_REG_M);
    Write_I2C(0x00);
    Stop_I2C();
}

Pedido de valores
Código: [Seleccione]
unsigned char M[6];
signed int X;

... ... ...

Open_I2C(MASTER, SLEW_OFF);
init_LSM303();

... ... ...

Start_I2C();
Write_I2C(write_LSM303_ACC);
Write_I2C(OUT_X_L_A);
Restart_I2C();

Write_I2C(read_LSM303_ACC);

M[0] = Read_I2C();
Ack_I2C();
M[1] = Read_I2C();
Ack_I2C();
M[2] = Read_I2C();
Ack_I2C();
M[3] = Read_I2C();
Ack_I2C();
M[4] = Read_I2C();
Ack_I2C();
M[5] = Read_I2C();

NotAck_I2C();
Stop_I2C();

X = (M[0]<<8) + M[1];



Título: Re: LSM303DLHC - os problemas de uma "primeira vez" - acelerometro
Enviado por: msr em 25 de Junho de 2014, 15:05
De quantos bits é que são os dados? 12, 13bit?
O facto dos dados de saida estarem representados em complemento para dois significa que tens um numero inteiro com sinal em que o bit mais significativo é 1 se for um numero negativo e 0 caso contrario. Como os dados têm 12 (ou 13 bit, confirma na datasheet) e as variaveis que usas no código C têm 16 ou 32 bit (numero suficiente de bits para guardares os dados do acelerometro), e para continuar a ser um número negativo tens de fazer extensão de sinal.
Este é o unico "truque" que precisas para obter valores correctos.

Em relação a converteres para m/s² tens de ver qual a escala que estás a usar (+-2g? 4g?) e fazeres uma regra de três simples para saberes a que corresponde o valor que lês do acelerómetro (valor máximo lido 2^12-1, caso os dados sejam de 12bit, confirma, corresponde à escala usada, 2g por exemplo)

http://en.wikipedia.org/wiki/Two%27s_complement (http://en.wikipedia.org/wiki/Two%27s_complement)
http://en.wikipedia.org/wiki/Sign_extension (http://en.wikipedia.org/wiki/Sign_extension)
http://en.wikipedia.org/wiki/Gravity_of_Earth (http://en.wikipedia.org/wiki/Gravity_of_Earth)
Título: Re: LSM303DLHC - os problemas de uma "primeira vez" - acelerometro
Enviado por: senso em 25 de Junho de 2014, 15:28
É só atirar-lhe com a biblioteca da adafruit para cima.
Dada a audiência do arduino, 99% dos problemas é não meterem pull ups nas linhas do i2c..
https://github.com/adafruit/Adafruit_LSM303
Título: Re: LSM303DLHC - os problemas de uma "primeira vez" - acelerometro
Enviado por: Dave em 25 de Junho de 2014, 15:41
Segundo o datasheet a saída é de 16bits - "? 16 bit data output".

No entanto também está escrito que para o ganho com FS a 00, corresponde 1mg/LSB, por isso para os +-2g dá 12 bits...

Vou dar uma vista de olhos pela biblioteca da adafruit e ver o que difere do que eu tenho na minha.




Qualquer dia ainda perco a cabeça e compro um arduino eheh  ;D
Título: Re: LSM303DLHC - os problemas de uma "primeira vez" - acelerometro
Enviado por: Dave em 25 de Junho de 2014, 16:04
Na biblioteca da adafruits, ele também nada fazem com o complemento para 2...

Ou seja, o valor tem de ser analisado depois para saber se deve ou não fazer o complemento.


Código: [Seleccione]
uint8_t xlo = Wire.read();
  uint8_t xhi = Wire.read();
  uint8_t ylo = Wire.read();
  uint8_t yhi = Wire.read();
  uint8_t zlo = Wire.read();
  uint8_t zhi = Wire.read();

  // Shift values to create properly formed integer (low byte first)
  accelData.x = (xlo | (xhi << 8)) >> 4;
  accelData.y = (ylo | (yhi << 8)) >> 4;
  accelData.z = (zlo | (zhi << 8)) >> 4;
Título: Re: LSM303DLHC - os problemas de uma "primeira vez" - acelerometro
Enviado por: msr em 25 de Junho de 2014, 16:53
Há uns tempos fiz um driver para este chip, vê lá se ajuda:

Código: [Seleccione]
void LSM303DLHC_readOutputs(uint8_t sel, int16_t *x, int16_t *y, int16_t *z)
{
  uint8_t *msb, *lsb, v1, v2;
  uint8_t sad, sad_w, sad_r, sub;
 
  if(x == 0 || y == 0 || z == 0)
    return;
 
  if(sel == LSM303DLHC_ACC) {
    msb = &v2;
    lsb = &v1;
    sub = LSM303DLHC_OUT_X_L_A;
  }
  else if(sel == LSM303DLHC_MAG) {
    msb = &v1;
    lsb = &v2;
    sub = LSM303DLHC_OUT_X_H_M;
  }
  else
    return;
   
  sad = sel;
  sad_w = (sad << 1) & 0xFE;
  sad_r = (sad << 1) | 0x01;
 
  hal_i2c_start();
  hal_i2c_write(sad_w);
  hal_i2c_idle(); // SAK
  hal_i2c_write(sub | 0x80); // SUB, read multiple bytes
  hal_i2c_idle(); // SAK
  hal_i2c_restart();
  hal_i2c_write(sad_r);
  hal_i2c_idle(); // SAK
  v1 = hal_i2c_read(); // Read X Acc (X Mag)
  hal_i2c_ack();
  v2 = hal_i2c_read();
  hal_i2c_ack();
  *x = (*msb << 8) | *lsb;
  v1 = hal_i2c_read(); // Read Y Acc (Z Mag)
  hal_i2c_ack();
  v2 = hal_i2c_read();
  hal_i2c_ack();
  if(sel == LSM303DLHC_ACC)
    *y = (*msb << 8) | *lsb;
  else
    *z = (*msb << 8) | *lsb;
  v1 = hal_i2c_read(); // Read Z Acc (Y Mag)
  hal_i2c_ack();
  v2 = hal_i2c_read();
  hal_i2c_nack();
  if(sel == LSM303DLHC_ACC)
    *z = (*msb << 8) | *lsb;
  else
    *y = (*msb << 8) | *lsb;
  hal_i2c_stop();
}

edit: como os dados de saída sao de 16bit não precisas de fazer extensão de sinal caso uses variaveis do tipo int16_t
Título: Re: LSM303DLHC - os problemas de uma "primeira vez" - acelerometro
Enviado por: Dave em 27 de Junho de 2014, 15:51
Olá.

Estive fora estes dias e cheguei hoje.

Em relação ao código que apresentas, msr, é precisamente o que estou a fazer.
*
* faço start i2c
* escrevo para o ACC
* indico o endereço de leitura
* faço restart i2c
* coloco o ACC para leitura
* vou ler os 6 bytes seguidos do eixo X, Y, Z, sempre com ACK entre leituras
* faço NACK
* stop i2c
* e por fim : X = (M[0] | (M[1] << 8 ));

O problema é que X varia, quando lhe mexo, de 64524 e 0....

 ???

Título: Re: LSM303DLHC - os problemas de uma "primeira vez" - acelerometro
Enviado por: Dave em 27 de Junho de 2014, 16:09
ahahahaha

Já descobri o meu erro!

Estava a fazer múltipla leitura, mas não tinha colocado o MSB a "1", o que fazia com que apenas fizesse uma leitura...

Write_I2C(OUT_X_L_A | 0x80);

Agora já tenho muitos valores eheheheh


Vamos manter este tópico em aberto, porque acho que mais dúvidas irão surgir :)


Obrigado.
Título: Re: LSM303DLHC - os problemas de uma "primeira vez" - acelerometro
Enviado por: Dave em 30 de Junho de 2014, 10:23
Olá novamente.

Estou a ter alguma dificuldade em perceber se devo ou não fazer algum tipo de calibração/ajuste ao acelerometro, pois estou a receber os dados em baixo (para o eixo X, OUT_X_L_A/OUT_X_H_A) sem qualquer tipo de vibração.

Tenho lido que é feita uma calibração para o magnetometro mas nada encontro para o acelerometro...

(https://lusorobotica.com/proxy.php?request=http%3A%2F%2Fi473.photobucket.com%2Falbums%2Frr100%2Fdaviddmmartins%2FCapture_zpscf64562c.png&hash=dace018364d81952bbe8fcb644820b23416f4039)

Há sem dúvida algo enorme que me continua a escapar.... o datasheet do IC parece-me algo muito mal explicado.
Já pensei se até não haverá um documento para toda a "familia" LSM303, mas nada encontro também no site da ST...

Alguma sugestão?
Título: Re: LSM303DLHC - os problemas de uma "primeira vez" - acelerometro
Enviado por: jm_araujo em 30 de Junho de 2014, 10:28
Força da gravidade?
Título: Re: LSM303DLHC - os problemas de uma "primeira vez" - acelerometro
Enviado por: Dave em 30 de Junho de 2014, 10:44
Isto é o que é mostrado quando oponho o eixo X à gravidade, ou seja, quando coloco a pastilha na vertical.

No geral aparece "16xxx", ao contrário dos "00xxx" da imagem anterior. Posso supor que aquele "1" será de 1g...
Se virar a placa no sentido contrário e colocar a favor do eixo, tenho as mesmas medições, mas com sinal negativo.

(https://lusorobotica.com/proxy.php?request=http%3A%2F%2Fi473.photobucket.com%2Falbums%2Frr100%2Fdaviddmmartins%2FCapture_zpsa78917fd.png&hash=135c8f248f47361fa6a7cb77411ecf62f37f14cf)

Mas, segundo o datasheet, eu deveria medir 0.001g por cada 1LSB, ou seja, com 1g, eu deveria medir 1000. Certo?
Mas eu estou a ter medidas significativas das dezenas de milhar.

(https://lusorobotica.com/proxy.php?request=http%3A%2F%2Fi473.photobucket.com%2Falbums%2Frr100%2Fdaviddmmartins%2FCapture_zps87037fd2.png&hash=e8909cb7396e9970ae5a995a904f4bef61c77428)
Título: Re: LSM303DLHC - os problemas de uma "primeira vez" - acelerometro
Enviado por: jm_araujo em 30 de Junho de 2014, 11:29
Lido assim por alto, entendi que os valor do FS defíne o valor "full scale".
Com FS a 00, full scale são 2g.
Em 16 bits signed, a fullscale de [32767, -32768] equivale a [+2g,-2g]
Fazendo um 3 simples com o valor mais usual quando estavas na vertical (16128):
aceleração=2g/32767*16128=0.984g , está lá perto, a diferença para 1g pode ser da precisão do alinhamento.

Agora reparei que os teus valores "saltam" em passos de 256 (-512,-768,-1024), o que quer dizer que não estás a receber os 8 bits LSB, ou vem a zero (talvez por causa do HR do CTRL_REG4_A??? não sei, a datasheet é pouco clara do que faz)

edit:
Mesmo sem o HR, devias estar a receber 10 bits de resolução (granularidade 2^(16-10)=64: saltar 64 entre medidas), mas estas a saltar 256. Estar a perder o byte LSB na leitura.

Tirado desta informação: http://www.pololu.com/product/1268 (http://www.pololu.com/product/1268)
Citar
The gyro, accelerometer, and magnetometer all output readings in a 16-bit format (obtained by combining the values in two 8-bit registers for each axis), but only the gyro readings contain 16 bits of precision. The accelerometer and magnetometer readings contain a maximum of 12 bits of precision; for the accelerometer, at least the lowest 4 bits of the output values are always 0, and for the magnetometer, the highest 4 bits of the output values are always 0.
The accelerometer gives low-resolution 10-bit readings by default (the lowest 6 bits of the output are always 0). To get the full 12-bit resolution, you must set the HR (high resolution) bit in the CTRL_REG4_A register.
Título: Re: LSM303DLHC - os problemas de uma "primeira vez" - acelerometro
Enviado por: Dave em 30 de Junho de 2014, 12:01
Ah... muito bem visto!

É daquelas coisas que, ler até li, mas não entendi muito bem o que queriam dizer com aquilo...
Mas poderá estar aí a justificação para que o meu byte menos significativo venha a zeros...

Outra coisa interessante que estive aqui a ver é que olhando para a resolução (1mg/LSB), +-2g ocupam 12bits (4g->4000). Se pensar (imaginar) que os bits vêm alinhados à esquerda e fizer 4 deslocamentos à direita (16bits-12bits = 4), talvez obtenha um valor mais próximo.

Fiz este exercício para +-2g e obtive leituras de 1008 (16128>>4 = 1008). Ora fazendo para +-4g, eu teria de obter metade desse valor (perto de 500). Fiz as leituras e obtive 8192, que deslocado 4 vezes para a direita dá os tais 512, perto do valor 500 como era previsível.

O que acham?
O datasheet é muito vago infelizmente....

Vou agora alterar o bit do HR.... sem dúvida muito bem observado jm_araujo ;).
Título: Re: LSM303DLHC - os problemas de uma "primeira vez" - acelerometro
Enviado por: Dave em 30 de Junho de 2014, 12:15
Aparentemente não tenho alterações no CTRL_REG4_A, a escrever 0x88.
Deveria "activar" o HR, mas continuo com a mesma "escala de saltos".
Título: Re: LSM303DLHC - os problemas de uma "primeira vez" - acelerometro
Enviado por: senso em 30 de Junho de 2014, 12:19
Acho extremamente estranho que não tenhas um byte inteiro de dados, ou estás a fazer algo errado na comunicação, ou estás a deitar o byte fora quando fazes a junção dos valores.
Título: Re: LSM303DLHC - os problemas de uma "primeira vez" - acelerometro
Enviado por: Dave em 30 de Junho de 2014, 12:24
Mas assim eu teria de estar a fazer algo byte não, byte sim...

De momento estou a ler os eixos todos e obtenho valores nos restantes, sempre com o byte menos significativo a zeros...

Código: [Seleccione]
            Start_I2C();
            Write_I2C(write_LSM303_ACC);
            Write_I2C(OUT_X_L_A | 0x80);
            Restart_I2C();

            Write_I2C(read_LSM303_ACC);

            M[0] = Read_I2C();
            Ack_I2C();
            M[1] = Read_I2C();
            Ack_I2C();
            M[2] = Read_I2C();
            Ack_I2C();
            M[3] = Read_I2C();
            Ack_I2C();
            M[4] = Read_I2C();
            Ack_I2C();
            M[5] = Read_I2C();

            NotAck_I2C();
            Stop_I2C();

            X = ((M[1] << 8 ) | M[0])>>4;
                sprintf(S, "Leitura X %.5d \n" , X);
                putrs_USART(S);   // send x
           

            Y = ((M[3] << 8 ) | M[2])>>4;
                sprintf(S, "Leitura Y %.5d \n" , Y);
                putrs_USART(S);   // send x



            Z = ((M[5] << 8 ) | M[4])>>4;
                sprintf(S, "Leitura Z %.5d \n" , Z);
                putrs_USART(S);   // send x

(https://lusorobotica.com/proxy.php?request=http%3A%2F%2Fi473.photobucket.com%2Falbums%2Frr100%2Fdaviddmmartins%2FCapture_zps7f5a2da4.png&hash=7767fa9a34586edeab0ae5716e01567153be4be9)
Título: Re: LSM303DLHC - os problemas de uma "primeira vez" - acelerometro
Enviado por: msr em 30 de Junho de 2014, 13:29
Deixo-te o meu driver completo: https://www.dropbox.com/sh/7zy1ux5s0hkg158/AADCS8RSlb-qVFzP7qhfVPEga (https://www.dropbox.com/sh/7zy1ux5s0hkg158/AADCS8RSlb-qVFzP7qhfVPEga)
Vê lá se ajuda.
Inclui uma função de teste que faz print de todos os registos e depois começa a ler os valores.
Título: Re: LSM303DLHC - os problemas de uma "primeira vez" - acelerometro
Enviado por: Dave em 30 de Junho de 2014, 14:07
Encontrei isto do datasheet de um acelerometro da mesma família, o LSM303DLH.

Citar
DR bits, in the normal-mode operation, select the data rate at which acceleration samples
are produced. In low-power mode they define the output data resolution. Table 21 shows all
the possible configurations for the DR1 and DR0 bits.

O meu CTRL_REG1_A, estava a 0x3F. O que fazia activar o Low Power Mode. Por algum motivo, no meio de tantas alterações, modifiquei isto também. Nas minhas folhas tinha 0x37... por isso já foi alteração à posteriori :(...

Os valores em baixo são extraídos antes de fazer as tais 4 deslocações à direita (para ter mais resolução).
Agora já recebo alterações no byte menos significativo...

(https://lusorobotica.com/proxy.php?request=http%3A%2F%2Fi473.photobucket.com%2Falbums%2Frr100%2Fdaviddmmartins%2FCapture_zpsd45a71e5.png&hash=051c7b91317b31ccd6cde377d2f57e5b634c6e55)
Título: Re: LSM303DLHC - os problemas de uma "primeira vez" - acelerometro
Enviado por: senso em 30 de Junho de 2014, 14:16
Continua a falhar alguma coisa, nem um numero impar, todos pares, não achas isso, digamos que estranho?
Título: Re: LSM303DLHC - os problemas de uma "primeira vez" - acelerometro
Enviado por: Dave em 30 de Junho de 2014, 14:21
Facto foi só falta de pontaria :)

No anterior é normal não aparecerem números ímpares, se a minha teoria se verificar aquilo estava justificado à esquerda.
Aqui já fiz os 4 deslocamentos e já aparecem números mais "confiáveis" ;).

(https://lusorobotica.com/proxy.php?request=http%3A%2F%2Fi473.photobucket.com%2Falbums%2Frr100%2Fdaviddmmartins%2FCapture_zps9174eaba.png&hash=6df54f02b853a0295c1ed482aad18fcd89cbcee5)
Título: Re: LSM303DLHC - os problemas de uma "primeira vez" - acelerometro
Enviado por: jm_araujo em 30 de Junho de 2014, 15:40
Agora sim, já tens valores mais bonitos ;D

Senso, não tinha números ímpares porque são valores de 12 bits alinhados à esquerda num inteiro de 16 por causa do sinal. Os 4 lsb são sempre 0.
Título: Re: LSM303DLHC - os problemas de uma "primeira vez" - acelerometro
Enviado por: Dave em 30 de Junho de 2014, 16:38
O datasheet do LSM303DLHC.... bem.... what piece of crap!

(https://lusorobotica.com/proxy.php?request=http%3A%2F%2Fi475.photobucket.com%2Falbums%2Frr118%2Ftwizted_mindz_myspace%2FHeadshot_by_maulwurf08.jpg&hash=24e16dcc8ae7ce271d4e682a059185e5c1de77b8)