Como rastrear a orientação com Arduino e acelerômetro ADXL345
Neste tutorial vamos aprender a medir o ângulo e a orientação da pista usando o Arduino e o sensor do acelerômetro ADXL345. Você pode assistir ao vídeo a seguir ou ler o tutorial escrito abaixo para obter mais detalhes.
Visão geral
Primeiro, explicarei como o sensor funciona e como ler os dados dele e, em seguida, usando o ambiente de desenvolvimento Processing, faremos uma visualização 3D da orientação do acelerômetro.
Como funciona o acelerômetro ADXL345
Para começar, vamos dar uma olhada em como funciona o sensor ADXL345. Este é um acelerômetro de 3 eixos que pode medir forças de aceleração estáticas e dinâmicas. A força gravitacional terrestre é um exemplo típico de força estática, enquanto as forças dinâmicas podem ser causadas por vibrações, movimentos e assim por diante.
A unidade de medida da aceleração é o metro por segundo ao quadrado (m/s^2). No entanto, os sensores do acelerômetro geralmente expressam as medidas em “g” ou gravidade. Um “g” é o valor da força gravitacional da Terra que é igual a 9,8 metros por segundo ao quadrado.
Assim, se tivermos um acelerômetro posicionado plano, com seu eixo Z apontando para cima, oposto à força gravitacional, a saída do eixo Z do sensor será de 1g. Por outro lado, as saídas X e Y serão zero, porque a força gravitacional é perpendicular a esses eixos e não os afeta em nada.
Se virarmos o sensor de cabeça para baixo, a saída do eixo Z será -1 g. Isso significa que as saídas do sensor devido à sua orientação à gravidade podem variar de -1g a +1g.
Então, de acordo com esses dados e usando alguns cálculos de trigonometria, podemos calcular o ângulo em que o sensor está posicionado.
Como ler dados do acelerômetro ADXL345 com Arduino
Ok, agora vamos ver como podemos ler os dados do acelerômetro ADXL345 usando o Arduino. Este sensor usa o protocolo I2C para comunicação com o Arduino, então precisamos apenas de dois fios para conectá-lo, mais os dois fios para alimentá-lo.
Você pode obter os componentes necessários para este tutorial do Arduino nos links abaixo:
- Acelerômetro ADXL345 ………………. Amazônia / Banggood / AliExpress
- Placa Arduino ………………………………..
- Breadboard e jump wires …………
Código Arduino do Acelerômetro ADXL345
Aqui está o código do Arduino para ler os dados do acelerômetro ADXL345.
/*
Arduino and ADXL345 Accelerometer Tutorial
by Dejan, https://howtomechatronics.com
*/
#include <Wire.h> // Wire library - used for I2C communication
int ADXL345 = 0x53; // The ADXL345 sensor I2C address
float X_out, Y_out, Z_out; // Outputs
void setup() {
Serial.begin(9600); // Initiate serial communication for printing the results on the Serial monitor
Wire.begin(); // Initiate the Wire library
// Set ADXL345 in measuring mode
Wire.beginTransmission(ADXL345); // Start communicating with the device
Wire.write(0x2D); // Access/ talk to POWER_CTL Register - 0x2D
// Enable measurement
Wire.write(8); // (8dec -> 0000 1000 binary) Bit D3 High for measuring enable
Wire.endTransmission();
delay(10);
}
void loop() {
// === Read acceleromter data === //
Wire.beginTransmission(ADXL345);
Wire.write(0x32); // Start with register 0x32 (ACCEL_XOUT_H)
Wire.endTransmission(false);
Wire.requestFrom(ADXL345, 6, true); // Read 6 registers total, each axis value is stored in 2 registers
X_out = ( Wire.read()| Wire.read() << 8); // X-axis value
X_out = X_out/256; //For a range of +-2g, we need to divide the raw values by 256, according to the datasheet
Y_out = ( Wire.read()| Wire.read() << 8); // Y-axis value
Y_out = Y_out/256;
Z_out = ( Wire.read()| Wire.read() << 8); // Z-axis value
Z_out = Z_out/256;
Serial.print("Xa= ");
Serial.print(X_out);
Serial.print(" Ya= ");
Serial.print(Y_out);
Serial.print(" Za= ");
Serial.println(Z_out);
}
Code language: Arduino (arduino)
Descrição: Então, primeiro precisamos incluir a biblioteca Wire.h que é usada para a comunicação I2C. Se você quiser aprender mais sobre como a comunicação I2C funciona e como usá-la com o Arduino, você pode conferir meu outro tutorial detalhado para isso.
Cada dispositivo que utiliza a comunicação I2C possui um endereço I2C único, e este endereço pode ser encontrado na ficha técnica do sensor (Ficha técnica ADXL345). Assim, uma vez que definimos o endereço e as variáveis para as três saídas, na seção de configuração, primeiro precisamos inicializar a biblioteca de fios e depois colocar o acelerômetro no modo de medição. Para isso, se olharmos novamente o datasheet, veremos que precisamos definir o bit D3 do registrador POWER_CTL em HIGH.
Então, usando a função beginTransmission() iniciamos a comunicação, então usando a função write() informamos qual registrador queremos acessar, e novamente usando a função write() colocamos o bit D3 em HIGH, escrevendo o número 8 em decimal que corresponde ao ajuste do bit D3 HIGH.
// Set ADXL345 in measuring mode
Wire.beginTransmission(ADXL345); // Start communicating with the device
Wire.write(0x2D); // Access/ talk to POWER_CTL Register - 0x2D
// Enable measurement
Wire.write(8); // (8dec -> 0000 1000 binary) Bit D3 High for measuring enable
Wire.endTransmission();
Code language: Arduino (arduino)
Na seção de loop agora lemos os dados do sensor. Os dados para cada eixo são armazenados em dois bytes ou registros. Podemos ver os endereços desses registros na folha de dados.
Para ler todos eles, começamos com o primeiro registrador, e usando a função requestionFrom() pedimos para ler os 6 registradores. Em seguida, usando a função read(), lemos os dados de cada registrador e, como as saídas são complementos de dois, combinamos adequadamente para obter os valores corretos.
// === Read acceleromter data === //
Wire.beginTransmission(ADXL345);
Wire.write(0x32); // Start with register 0x32 (ACCEL_XOUT_H)
Wire.endTransmission(false);
Wire.requestFrom(ADXL345, 6, true); // Read 6 registers total, each axis value is stored in 2 registers
X_out = ( Wire.read()| Wire.read() << 8); // X-axis value
X_out = X_out/256; //For a range of +-2g, we need to divide the raw values by 256, according to the datasheet
Y_out = ( Wire.read()| Wire.read() << 8); // Y-axis value
Y_out = Y_out/256;
Z_out = ( Wire.read()| Wire.read() << 8); // Z-axis value
Z_out = Z_out/256;
Code language: Arduino (arduino)
Os valores de saída do sensor realmente dependem da sensibilidade selecionada, que pode variar de +- 2g a +-16g. A sensibilidade padrão é +-2g, por isso precisamos dividir a saída por 256 para obter valores de -1 a +1g. O 256 LSB/g significa que temos 256 contagens por g.
Dependendo da aplicação, podemos selecionar a sensibilidade apropriada. Nesse caso, para orientação de rastreamento, a sensibilidade de +-2g é boa, mas para aplicações em que precisamos detectar uma força de aceleração mais alta de movimentos bruscos, choques e assim por diante, podemos escolher algumas das outras faixas de sensibilidade usando o registro DATA_FORMAT e seus bits D1 e D0.
Calibração do acelerômetro ADXL345
No entanto, uma vez lidos os dados, podemos simplesmente imprimi-los no monitor serial para verificar se os valores estão conforme o esperado. No meu caso, os valores que eu estava obtendo não eram exatamente como deveriam ser, especialmente o eixo Z que teve um erro perceptível de 0,1g.
Para resolver esse problema, precisamos calibrar o acelerômetro usando os 3 registros de calibração de deslocamento, e veja como podemos fazer isso. Então, precisamos posicionar o sensor plano e imprimir os valores RAW sem dividi-los por 256.
A partir daqui podemos notar o quanto as saídas estão desligadas, no meu caso, a saída Z ficou em torno de 283. Isso é uma diferença de 27 no positivo. Agora precisamos dividir esse valor por 4, e isso nos dará o número que precisamos escrever no registrador de deslocamento do eixo Z. Se carregarmos o código agora, a saída do eixo Z será exatamente 256, ou 1g como deveria ser.
// This code goes in the SETUP section
// Off-set Calibration
//X-axis
Wire.beginTransmission(ADXL345);
Wire.write(0x1E); // X-axis offset register
Wire.write(1);
Wire.endTransmission();
delay(10);
//Y-axis
Wire.beginTransmission(ADXL345);
Wire.write(0x1F); // Y-axis offset register
Wire.write(-2);
Wire.endTransmission();
delay(10);
//Z-axis
Wire.beginTransmission(ADXL345);
Wire.write(0x20); // Z-axis offset register
Wire.write(-7);
Wire.endTransmission();
delay(10);
Code language: Arduino (arduino)
Se necessário, devemos calibrar o outro eixo usando o mesmo método. E apenas uma nota rápida que esta calibração não é gravada permanentemente nos registros. Precisamos escrever esses valores nos registradores a cada inicialização do sensor.
Quando terminarmos a calibração, podemos finalmente calcular o Roll and Pitch, ou a rotação em torno do eixo X e a rotação em torno do eixo Y em graus, usando essas duas fórmulas.
// Calculate Roll and Pitch (rotation around X-axis, rotation around Y-axis)
roll = atan(Y_out / sqrt(pow(X_out, 2) + pow(Z_out, 2))) * 180 / PI;
pitch = atan(-1 * X_out / sqrt(pow(Y_out, 2) + pow(Z_out, 2))) * 180 / PI;
Code language: Arduino (arduino)
Para obter mais detalhes sobre como essas fórmulas funcionam, você pode verificar esta nota de aplicação da Freescale Semiconductor.
Acompanhamento de orientação do acelerômetro do Arduino e ADXL345 – visualização 3D
Ok, vamos fazer o exemplo de visualização 3D do acelerômetro agora.
Portanto, estamos usando o mesmo código, que envia os valores de Roll e Pitch pela porta serial. Aqui está o código completo do Arduino:
/*
Arduino and ADXL345 Accelerometer - 3D Visualization Example
by Dejan, https://howtomechatronics.com
*/
#include <Wire.h> // Wire library - used for I2C communication
int ADXL345 = 0x53; // The ADXL345 sensor I2C address
float X_out, Y_out, Z_out; // Outputs
float roll,pitch,rollF,pitchF=0;
void setup() {
Serial.begin(9600); // Initiate serial communication for printing the results on the Serial monitor
Wire.begin(); // Initiate the Wire library
// Set ADXL345 in measuring mode
Wire.beginTransmission(ADXL345); // Start communicating with the device
Wire.write(0x2D); // Access/ talk to POWER_CTL Register - 0x2D
// Enable measurement
Wire.write(8); // Bit D3 High for measuring enable (8dec -> 0000 1000 binary)
Wire.endTransmission();
delay(10);
//Off-set Calibration
//X-axis
Wire.beginTransmission(ADXL345);
Wire.write(0x1E);
Wire.write(1);
Wire.endTransmission();
delay(10);
//Y-axis
Wire.beginTransmission(ADXL345);
Wire.write(0x1F);
Wire.write(-2);
Wire.endTransmission();
delay(10);
//Z-axis
Wire.beginTransmission(ADXL345);
Wire.write(0x20);
Wire.write(-9);
Wire.endTransmission();
delay(10);
}
void loop() {
// === Read acceleromter data === //
Wire.beginTransmission(ADXL345);
Wire.write(0x32); // Start with register 0x32 (ACCEL_XOUT_H)
Wire.endTransmission(false);
Wire.requestFrom(ADXL345, 6, true); // Read 6 registers total, each axis value is stored in 2 registers
X_out = ( Wire.read() | Wire.read() << 8); // X-axis value
X_out = X_out / 256; //For a range of +-2g, we need to divide the raw values by 256, according to the datasheet
Y_out = ( Wire.read() | Wire.read() << 8); // Y-axis value
Y_out = Y_out / 256;
Z_out = ( Wire.read() | Wire.read() << 8); // Z-axis value
Z_out = Z_out / 256;
// Calculate Roll and Pitch (rotation around X-axis, rotation around Y-axis)
roll = atan(Y_out / sqrt(pow(X_out, 2) + pow(Z_out, 2))) * 180 / PI;
pitch = atan(-1 * X_out / sqrt(pow(Y_out, 2) + pow(Z_out, 2))) * 180 / PI;
// Low-pass filter
rollF = 0.94 * rollF + 0.06 * roll;
pitchF = 0.94 * pitchF + 0.06 * pitch;
Serial.print(rollF);
Serial.print("/");
Serial.println(pitchF);
}
Code language: Arduino (arduino)
Agora, no ambiente de desenvolvimento Processing, precisamos receber esses valores e usá-los para girar o objeto 3D que vamos criar. Aqui está o código de processamento completo:
/*
Arduino and ADXL345 Accelerometer - 3D Visualization Example
by Dejan, https://howtomechatronics.com
*/
import processing.serial.*;
import java.awt.event.KeyEvent;
import java.io.IOException;
Serial myPort;
String data="";
float roll, pitch;
void setup() {
size (960, 640, P3D);
myPort = new Serial(this, "COM8", 9600); // starts the serial communication
myPort.bufferUntil('\n');
}
void draw() {
translate(width/2, height/2, 0);
background(33);
textSize(22);
text("Roll: " + int(roll) + " Pitch: " + int(pitch), -100, 265);
// Rotate the object
rotateX(radians(roll));
rotateZ(radians(-pitch));
// 3D 0bject
textSize(30);
fill(0, 76, 153);
box (386, 40, 200); // Draw box
textSize(25);
fill(255, 255, 255);
text("www.HowToMechatronics.com", -183, 10, 101);
//delay(10);
//println("ypr:\t" + angleX + "\t" + angleY); // Print the values to check whether we are getting proper values
}
// Read data from the Serial Port
void serialEvent (Serial myPort) {
// reads the data from the Serial Port up to the character '.' and puts it into the String variable "data".
data = myPort.readStringUntil('\n');
// if you got any bytes other than the linefeed:
if (data != null) {
data = trim(data);
// split the string at "/"
String items[] = split(data, '/');
if (items.length > 1) {
//--- Roll,Pitch in degrees
roll = float(items[0]);
pitch = float(items[1]);
}
}
}
Code language: Arduino (arduino)
Descrição: Então, aqui, precisamos incluir a biblioteca serial, definir a porta serial e a taxa de transmissão que precisa corresponder à taxa de transmissão do esboço do Arduino carregado. Em seguida, lemos os dados recebidos e os colocamos nas variáveis roll e pitch apropriadas. No loop de desenho principal, usamos esses valores para girar o objeto 3D e, neste caso, é uma caixa simples com uma cor específica e um texto nela.
Se executarmos o esboço, o objeto 3D aparecerá e rastreará a orientação do sensor do acelerômetro. Podemos notar aqui que o objeto está realmente um pouco instável e isso ocorre porque o acelerômetro captura não apenas a força gravitacional, mas também pequenas forças geradas pelos movimentos de nossa mão. Para obter um resultado mais suave, podemos usar um filtro passa-baixa simples. Aqui eu implementei esse filtro no código do Arduino, que pega 94% do estado anterior e adiciona 6% do estado ou ângulo atual.
// Low-pass filter
rollF = 0.94 * rollF + 0.06 * roll;
pitchF = 0.94 * pitchF + 0.06 * pitch;
Code language: Arduino (arduino)
Com este filtro, podemos notar que o objeto se move muito mais suavemente agora, mas também há um efeito colateral e isso é uma resposta mais lenta. Também podemos notar que estamos perdendo a guinada, ou rotação em torno do eixo Z. Usando apenas os dados do acelerômetro de 3 eixos, não podemos calcular a guinada.
Para fazer isso e melhorar o desempenho geral do nosso sensor de rastreamento de orientação, precisamos incluir um sensor adicional, um giroscópio, e fundir seus dados com o acelerômetro.
Portanto, podemos usar o acelerômetro ADXL345 em combinação com algum sensor de giroscópio ou usar o MPU6050 IMU que possui acelerômetro de 3 eixos e giroscópio de 3 eixos integrados em um único chip. Você pode encontrar um tutorial mais detalhado sobre este sensor no meu próximo vídeo.
Espero que tenham gostado deste tutorial e aprendido algo novo. Sinta-se à vontade para fazer qualquer pergunta na seção de comentários abaixo e não se esqueça de verificar minha coleção de projetos do Arduino.
Processo de manufatura
- Controle do Servo Motor com Arduino e MPU6050
- u-blox LEA-6H 02 Módulo GPS com Arduino e Python
- Como ler a temperatura e umidade em Blynk com DHT11
- Reconhecimento de fala e síntese com Arduino
- Como fazer música com um Arduino
- Como usar NMEA-0183 com Arduino
- Como usar o Modbus com Arduino
- Máquina de café inteligente com Arduino e Bluetooth
- Luz inteligente animada com Alexa e Arduino
- Reconhecimento de fala com Arduino e BitVoicer Server