Progetto RC

Accelerometro Arduino e ADXL345

Come funziona l’accelerometro ADXL345

Per cominciare, diamo un’occhiata a come funziona il sensore ADXL345. Questo è un accelerometro a 3 assi in grado di misurare forze di accelerazione sia statiche che dinamiche. La forza gravitazionale terrestre è un tipico esempio di forza statica, mentre le forze dinamiche possono essere causate da vibrazioni, movimenti e così via.

L’unità di misura dell’accelerazione è metro al secondo quadrato (m / s ^ 2). Tuttavia, i sensori dell’accelerometro di solito esprimono le misurazioni in “g” o gravità. Una “g” è il valore della forza gravitazionale terrestre che è pari a 9,8 metri al secondo quadrato.

Quindi, se abbiamo un accelerometro posizionato piatto, con il suo asse Z rivolto verso l’alto, opposto alla forza gravitazionale, l’uscita dell’asse Z del sensore sarà 1 g. D’altra parte, le uscite X e Y saranno zero, perché la forza gravitazionale è perpendicolare a questi assi e non li influenza affatto.

Se capovolgiamo il sensore capovolto, l’uscita dell’asse Z sarà -1 g. Ciò significa che le uscite del sensore a causa del suo orientamento alla gravità possono variare da -1g a + 1g.

Quindi in base a questi dati e utilizzando alcuni calcoli trigonometrici, possiamo calcolare l’angolo al quale è posizionato il sensore.

Come leggere i dati dell’accelerometro ADXL345 con Arduino

Ok, ora vediamo come possiamo leggere i dati dell’accelerometro ADXL345 usando Arduino. Questo sensore utilizza il protocollo I2C per la comunicazione con Arduino quindi abbiamo bisogno solo di due fili per collegarlo, più i due fili per alimentarlo.

Puoi ottenere i componenti necessari per questo tutorial di Arduino:

  • ADXL345 Accelerometer
  • Arduino Board
  • Breadboard and Jump Wires

Codice Arduino dell’accelerometro ADXL345

Ecco il codice Arduino per leggere i dati dell’accelerometro ADXL345.

#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);
}

Descrizione

Quindi prima dobbiamo includere la libreria Wire.h che viene utilizzata per la comunicazione I2C. Se vuoi saperne di più su come funziona la comunicazione I2C e su come usarla con Arduino puoi controllare il mio altro tutorial dettagliato per questo.

Ogni dispositivo che utilizza la comunicazione I2C ha un indirizzo I2C univoco e questo indirizzo si trova nella scheda tecnica del sensore (Scheda tecnica ADXL345).Per fare ciò, se guardiamo nuovamente il datasheet, possiamo vedere che dobbiamo impostare il bit D3 del registro POWER_CTL su HIGH.

Quindi, utilizzando la funzione beginTransmission () avviamo la comunicazione, quindi utilizzando la funzione write () diciamo a quale registro vogliamo accedere, e ancora utilizzando la funzione write () impostiamo il bit D3 HIGH, scrivendo il numero 8 in decimale che corrisponde all’impostazione del 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();

Nella sezione loop ora leggiamo i dati dal sensore. I dati per ogni asse vengono memorizzati in due byte o registri. Possiamo vedere gli indirizzi di questi registri dal datasheet.

Descrizione

Per leggerli tutti, partiamo dal primo registro, e usando la funzione requestionFrom () chiediamo di leggere i 6 registri. Quindi, utilizzando la funzione read (), leggiamo i dati da ciascun registro e, poiché gli output sono complementi a due, li combiniamo in modo appropriato per ottenere i valori corretti.

// === 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;

I valori di uscita dal sensore dipendono effettivamente dalla sensibilità selezionata, che può variare da + – 2g a + -16g. La sensibilità predefinita è + -2g, ecco perché dobbiamo dividere l’output per 256 per ottenere valori da -1 a + 1g. 256 LSB / g significa che abbiamo 256 conteggi per g.

A seconda dell’applicazione possiamo selezionare la sensibilità appropriata. In questo caso, per l’orientamento del tracciamento, la sensibilità di + -2g va bene, ma per applicazioni in cui dobbiamo rilevare una forza di accelerazione maggiore da movimenti improvvisi.

Calibrazione accelerometro ADXL345

Tuttavia, una volta letti i dati, possiamo semplicemente stamparli sul monitor seriale per verificare se i valori sono quelli previsti. Nel mio caso, i valori che stavo ottenendo non erano esattamente come dovrebbero essere, in particolare l’asse Z che aveva un errore evidente di 0,1 g.

Per risolvere questo problema, dobbiamo calibrare l’accelerometro utilizzando i 3 registri di calibrazione offset, ed ecco come possiamo farlo. Quindi, dobbiamo posizionare il sensore in piano e stampare i valori RAW senza dividerli per 256.

Da qui ora possiamo notare quanto sono spente le uscite, nel mio caso l’uscita Z era intorno a 283. Questa è una differenza di 27 in positivo. Ora dobbiamo dividere questo valore per 4, e questo fornirà il numero che dobbiamo scrivere nel registro di offset dell’asse Z. Se cariciamo il codice ora, l’output dell’asse Z sarà esattamente 256, o 1g come dovrebbe essere.

// 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);

Se necessario, dovremmo calibrare l’altro asse utilizzando lo stesso metodo. E solo una breve nota che questa calibrazione non viene scritta in modo permanente nei registri. Dobbiamo scrivere questi valori nei registri ad ogni accensione del sensore.

Una volta terminata la calibrazione, ora possiamo finalmente calcolare il Roll e Pitch, o la rotazione attorno all’asse X e la rotazione attorno all’asse Y in gradi, usando queste due formule.

// 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;

Tracciamento dell’orientamento dell’accelerometro Arduino e ADXL345 – Visualizzazione 3D

Ok, facciamo ora l’esempio di visualizzazione 3D dell’accelerometro.

Quindi, stiamo usando lo stesso codice, che invia i valori Roll e Pitch attraverso la porta seriale. Ecco il codice Arduino completo:

#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);
}

Ora nell’ambiente di sviluppo Processing abbiamo bisogno di ricevere questi valori e usarli per ruotare l’oggetto 3D che creeremo. Ecco il codice di elaborazione completo:

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]);
    }
  }
}

Descrizione

Quindi qui, dobbiamo includere la libreria seriale, definire la porta seriale e il baud rate che deve corrispondere al baud rate dello sketch Arduino caricato. Quindi leggiamo i dati in arrivo e li inseriamo nelle variabili di rollio e beccheggio appropriate. Nel ciclo di disegno principale, usiamo questi valori per ruotare l’oggetto 3D, e in questo caso si tratta di una semplice scatola con un colore particolare e un testo sopra.

Se eseguiamo lo schizzo, l’oggetto 3D apparirà e seguirà l’orientamento del sensore dell’accelerometro. Possiamo notare qui che l’oggetto è effettivamente un po ‘traballante e questo perché l’accelerometro cattura non solo la forza gravitazionale, ma anche piccole forze generate dai movimenti della nostra mano. Per ottenere risultati più fluidi, possiamo utilizzare un semplice filtro passa-basso. Qui ho implementato un tale filtro nel codice Arduino, che prende il 94% dello stato precedente e aggiunge il 6% dello stato o dell’angolo corrente.

// Low-pass filter
  rollF = 0.94 * rollF + 0.06 * roll;
  pitchF = 0.94 * pitchF + 0.06 * pitch;

Con questo filtro, possiamo notare che l’oggetto si muove molto più facilmente ora, ma c’è anche un effetto collaterale e questa è una reattività più lenta. Possiamo anche notare che ci manca l’imbardata, o rotazione attorno all’asse Z. Utilizzando solo i dati dell’accelerometro a 3 assi non siamo in grado di calcolare l’imbardata.

Quindi, possiamo utilizzare l’accelerometro ADXL345 in combinazione con un sensore giroscopio o utilizzare l’IMU MPU6050 che ha sia l’accelerometro a 3 assi che il giroscopio a 3 assi integrati su un singolo chip.

Mostra di più

Articoli Correlati

Başa dön tuşu
Kapalı