Acelerómetro Implementação de um sensor de orientação no Arduino e no Processing

acel2

 

youtube quick previewhttp://www.youtube.com/watch?v=yAlQlf6zgPg

Neste tutorial iremos desenvolver, a partir de um acelerómetro de 3 eixos, um sensor de Attitude, ou por outras palavras, um sistema que determina em tempo real a orientação de um objecto no espaço.

Este post subdivide-se em 3 partes. Na primeira, faremos uma introdução descritiva ao modo de funcionamento do acelerómetro. São abordados diferentes cenários de utilização e discutidas as suas limitações.

Num segundo momento, explicaremos de forma detalhada a sua implementação no arduino,

Na última parte, será apresentado um exemplo em Processing e outro em Unity3D (próximo post).

O acelerómetro que serve de base a este tutorial é a unidade de baixo custo ADXL335.

adxl335-500x500 sku_225179_1

No entanto,quer os textos de apoio quer os exemplos são válidos genericamente para qualquer outro acelerómetro, desde que este possua saídas analógicas e o leitor tenha acesso à sua folha técnica.

.

.

Como funciona um acelerómetro de 3 eixos (3D)?

O acelerómetro digital de baixo custo  é um sensor que mede indirectamente a aceleração através da força a que o sensor está sujeito em cada um dos três eixos. Se uma força actuar sobre um eixos do sensor, a aceleração é proporcional e de sentido inverso ao valor obtido.

Quando o acelerómetro está em repouso, por exemplo pousado numa superfície plana, o seu valor para o eixo Z é igual a -1g (e zero os eixos X e Y). Este valor (x= 0,y=0, z=1) corresponde ao vector da força da gravidade. Se rodarmos o acelerómetro de modo a ficar com outro eixo voltado para baixo, digamos o eixo X, o valor comunicado correspodenrá ao vector (x=1,y=0,z=0).

.

.

Cenário 1. Attitude Sensor

Assim, sempre que o acelerómetro estiver em repouso é possível, através de cálculos trignométricos, determinar com exactidão a orientação tridimensional do sensor, o que em si é tarefa simples.

145

O primeiro gráfico representa uma situação em que o acelerómetro se encontra em repouso (pousado numa superfície). O sensor medirá o vector da força de gravidade a actuar sobre o eixo Z. Se rodarmos o acelerómetro, digamos, ao longo do eixo Z, essa rotação irá reprecutir-se no sistema de coordenadas (gráfico do centro). Repare-se que o vector da força da gravidade, face ao mundo, permanece na vertical. O output do acelerómetro está representado no gráfico à direita. Calculando o ângulo entre este vector e os 3 eixos obtemos a orientação 3D do acelerómetro, ou a sua atitude.

.

.

Cenário 2. TILT Sensor

Um sensor TILT mede as forças que agem sobre um obejcto e que, geralmente, provocam a sua translação no espaço. A partir da aceleração é possível inferir a velocidade e a aceleração.

1 2 3

O acelerómetro, além de medir a força da gravidade, mede também todas as forças a que o sensor está sujeito. Este conjunto de forças, chamada força de rede, é o resultado da soma algébrica de todas as forças. Se por exemplo empurrarmos o sensor, que se encontrava pousado numa superfície plana e em repouso (gráfico da esquerda), ao longo do X (gráfico do centro), o output do acelerómetro corresponde à força de rede, ou seja, a soma de todas as forças (gráfico da direita). Também, neste caso, é fácil do ponto de vista matemático inferir o valor da força que o deslocou (Fp), bastando para isso subtrair ao output do sensor (Fn) o vector gravidade (Fg).

.

.

IMU. Inertial Motion Unity

A principal limitação do acelerómetro consiste na impossibilidade de conjugação dos dois cenários. Um sistema de sensoriamento inercial, composto unicamente por um acelerómetro, pode estimar com exactidão a orientação de um objecto caso este se encontre imóvel ou em repouso (cenário 1. Atitude Sensor), e consegue estimar a translação sempre que o movimento não envolva rotações (cenário 2. Tilt sensor). Infelizmente estas duas situações raramente descrevem os cenários reais que envolvem desde aparelhos voadores, quer gestos humanos realizados no manuseamento de objectos.

3 6

Quando um objecto (que possua um acelerómetro incorporado) é manuseado, está sujeito a movimentos de translação e simultaneamente de rotação. Reportando ao exemplo anterior no qual um objecto em repouso é movido lateralmente ao longo do eixo X (gráfico à esquerda), se acrescentarmos uma rotação (gráfico da direita) torna-se impossível a partir do vector obtido do acelerómetro ( o vector agregado da força de rede Fn) calcular as componentes individuais de rotação (Fg) e de translação (Fp) que lhes deream origem.

Um sistema que permita discriminar estas componentes é capaz de estimar simultaneamente a posição e a orientação de um objecto. Tais sistemas denominam-se por IMU – Inertial Motion Units, e geralmente requerem, além do acelerómetro, outras sensores como o giroscópio, o magnetómetro (bússula digital) ou até mesmo GPS, quando estese encontra diposponível e é adequado ao contexto de aplicação. Combinando o output de várias unidades é possível estimar não só a orientação como também a posição de um objecto.

Para mais informação acerca do funcionamento do acelerómetro, do giroscópio e de como combinar ambos para desenvolver um IMU, consulte o excelente guia de Starlino.

.

.

Implementação no Arduino de um sensor de orientação

O próximo passo é desenvovler um programa no Arduino cujo obejctivo é converter os valores dos acelerómetro em unidades físicas, tais como a aceleração medida em Força g ou a orientação medida em graus. Inspirando-nos no guia de Starlino iremos implementar o código no Arduino e explicar passo-a-passo as várias etapas.

– O nosso programa irá comunicar os ângulos da orientação do acelerómetro por via da porta de comunicação. No bloco Setup necessitamos de inicializar o objecto Serial.

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

.

– No início do progrma, criamos 3 variáveis globais para guardar o output do sensor.

int ax,ay,az;

.

– Em seguida, já no interior do bloco loop, vamos declarar e ler o output analógico do sensor.

void loop(){
ax=analogRead(0);
ay=analogRead(1);
az=analogRead(2);

.

– Tendo em consideração que estamos a alimentar a unidade com 3.3V e o valor de referência do cenversor analógico-digital é de 5V, teremos de efectuar uma simples conversão.

Este procedimento não é necessário caso conecte 3.3V ao pino AREF ou caso esteja a usar um acelerómetro alimentado a 5V (atenção que a maior parte dos acelerómetros trabalham a 3~3.3V e podem ser danificados se os alimentar a 5V).

ax=ax*5/3.3;
ay=ay*5/3.3;
az=az*5/3.3;

.

– As folhas técnicas dos acelerómentros costumam representar  as grandezas em volts. Uma simples operação permitirá converter os valores 10 bits (0-1023) do conversor analógico do arduino para valores em volts.

float vx = ax*3.3/1023;
float vy = ay*3.3/1023;
float vz = az*3.3/1023;

.

– De acordo com a folha técnica do acelerómetro, o valor da voltagem que corresponde a uma aceleração nula, denominada Zero g, é de 1.5V quando a unidade é alimentada com 3V (Vs).
Como o output do Zero g é proporcional (ratiometric) podemos calcular a relação para 3.3V
Assim:

float z= 1.5*3.3/3; //z=1.65

.

– Subtraímos o Zero v e obtemos os dados centrados na origem.

vx-=z;
vy-=z;
vz-=z;

.

– Finalmente estamos em condições de calcular a aceleração medida em g’s (por exemplo, gravidade g=1, ou seja 9.8 m/s^2).
PAra converter para g’s os valores medidos em Volts necessitamos de procurar na folha técnica os parâmetros de sensibilidade, geralmente expressos em mV/g. Também neste caso, os valores são ratiometric.
No nosso caso, a sensibilidade é de 300/g para uma Vs=3V. Ou seja, quando o acelerómetro é alimentado com 3V, cada 300mv equivalem a uma aceleração de 1g.
Iremos num primeiro momento ajustar a sensibildidade ao nosso Vs, que como sabemos é de 3.3V, e em seguida dividir por 1000 porque precisamos ajustar a sensibilidade para Volts e não em mVolts.
Por fim, multiplicamos os valores obtidos nos passos anteriores pelo coeficiente de sensibilidade e obtemos os valores expresso em força g.

float sensitivity = 300*3.3/3; //sensitivity=330
sensitivity=sensitivity/1000;
float gx = vx*sensitivity;
float gy = vy*sensitivity;
float gz = vz*sensitivity;

Recorremos à seguinte fórmula para a conversão de força g em ângulos:
angleX = arccos(gx/m)
em que m é o comprimento do vector da força (de gravidade).

float m=sqrt(gx*gx+gy*gy+gz*gz);
float angleX=acos(gx/m);
float angleY=acos(gy/m);
float angleZ=acos(gz/m);

.

– Finalmente, após converter os ângulo radianos para graus, iremos enviá-los pela porta série.

angleX=angleX*180/3.14;
angleY=angleY*180/3.14;
angleZ=angleZ*180/3.14;
Serial.print(int(angleX)); Serial.print(",");
Serial.print(int(angleY)); Serial.print(",");
Serial.print(int(angleZ)); Serial.print(",");
Serial.println(); delay(50);

.
.

Exemplo no arduino e processing

Ligue o acelerómetro ao arduino.
acel




Juntando tudo num único sketch

arduinoheader

#include <math.h>

int zx0=335;
int zy0=335;
int zz0=335;
int ax,ay,az;

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

void loop(){

 // read accelerometer output
 ax=analogRead(3);
 ay=analogRead(4);
 az=analogRead(5);

 // arduino analog maps 0v-5v into 0-1023
 // most accelerometers work at ~3v
 // skip this part if:
 // 1.you connected 3.3v to arduino pin AREF
 // 2.your acelerometer is working at 5v
 // - remember, most of units doesnt work with 5v
 ax=ax*5/3.3;
 ay=ay*5/3.3;
 az=az*5/3.3;

 // calculate voltage
 float vx = ax*3.3/1023;
 float vy = ay*3.3/1023;
 float vz = az*3.3/1023; 

 //from accelerometer's datasheet, get zero g voltage value.
 //most of the time value is for 3v power supply.
 //we can easly calculate for 3.3v
 // since the output typically is ratiometric (proportional)
 // in this case, datasheet shows Zg=1.5v for Vs=3
 float z= 1.5*3.3/3; //z=1.65

 // set the origin to Zero-g voltage level
 vx-=z;
 vy-=z;
 vz-=z; 

 // now we can convert voltage to force g (for instance gravity: 9.8 m/s^2)
 // find in the datasheet sensitivy, usually expressed in mV/g.
 // for our case sensitivity equals 300/g for Vs=3V.
 // again the former is ratiometric to power supply (Vs=3.3V)
 // so we need to transform this number first
 float sensitivity = 300*3.3/3; //sensitivity=330

 // and convert it from milli-voltage to Voltage
 // since our readings are in voltage
 sensitivity=sensitivity/1000;

 // now we can aply the formula to our readings
 // and get force (g)

 float gx = vx*sensitivity;
 float gy = vy*sensitivity;
 float gz = vz*sensitivity;

 // Determine the angle between the accelerometer and axis xyz
 // using the formula
 // angleX = arccos(gx/m)
 // where m (magnitude or length) is
 // m = Sq.root(x*x + y*y + z*z)

 float m=sqrt(gx*gx+gy*gy+gz*gz);
 float angleX=acos(gx/m);
 float angleY=acos(gy/m);
 float angleZ=acos(gz/m);

 // convert angles from radians to degrees

 angleX=angleX*180/3.14;
 angleY=angleY*180/3.14;
 angleZ=angleZ*180/3.14;

 Serial.print(int(angleX));Serial.print(",");
 Serial.print(int(angleY));Serial.print(",");
 Serial.print(int(angleZ));Serial.print(",");
 Serial.println(); 

 delay(50);
}

Para termos uma representação visual do algoritmo desenvolvemos uma aplicação simples no Processing. Esta úlitma, por sua vez, recebe os dados do Arduino e aplica em tempo real a orientação (attitude)  a uma caixa 3D.

processing_header

import processing.serial.*;

Serial porta;
int x,y,z;
PFont fonte;

void setup()
{
 size(500, 500, P3D);
 noStroke();
 fill(255, 120,0);
 stroke(255);
 strokeWeight(4);
 background(0,100,70);

 String portName = Serial.list()[0];
 porta = new Serial(this, portName, 9600);
 porta.bufferUntil(10);
}

void draw()
{
 background(0);
 text(x + " , " + y ,40,45);
 translate(width/2, height/2);
 rotateX(x*(TWO_PI)/360);
 rotateY(y*(TWO_PI)/360);
 box(100, 100, 100);

}

void serialEvent(Serial p) {
 String buffer = (porta.readString());
 int[] val = int(split(buffer, ','));
 println(buffer);
 x=val[0];
 y=val[1];
 z=val[2];
}

.

.

.

.

.

Anúncios