Electrical – ADXL345 GY-291 weird measures

accelerometerarduinosensorspi

currently I am trying to connect several ADXL345 to an Arduino Nano. I followed the Sparkfun Tutorial on how to do this (https://www.sparkfun.com/tutorials/240). Long story short, I connected two ADXL345 to the Arduino and can read the measures from it, but the values seem to be completely wrong.

So when I lay bot flat on the table, I'd expect the measures to be approx 0,0,1g (x,y,z).

When I lay both of them flat on the table I get:

SelectedChip: 9- -0.5460000038,-0.4679999828,-0.0077999997
SelectedChip: 10- -0.2262000083,-0.5460000038,-0.0077999997

When I turn around both Chips 180°, I'd expect the measures to be approx 0,0,-1. But I get:

SelectedChip: 9- -0.6006000041,-0.3977999877,-0.0077999997  <-- Z-Axis does not change at all with this one
SelectedChip: 10- -0.2574000120,-0.4368000030,2.9873998641

When I tilt both to 90° I' expect the measures to be approx 0,1,0. But I get:

SelectedChip: 9- -0.5460000038,-1.6223999023,-0.0077999997
SelectedChip: 10- -0.1949999904,-1.7081999778,-0.0546000003

When I shake them I get the following:

SelectedChip: 9- -3.3539998531,-3.9935998916,-0.4835999965
SelectedChip: 10- 0.1715999984,-0.0077999997,-0.0077999997
SelectedChip: 9- -0.0311999988,-0.4368000030,-0.0077999997
SelectedChip: 10- -1.8017998695,2.4570000171,-0.0077999997
SelectedChip: 9- -0.2417999982,-0.6083999633,-0.0077999997
SelectedChip: 10- -0.9671999931,-3.4085998535,-0.2963999748
SelectedChip: 9- 0.7409999847,-0.6941999912,-0.0077999997
SelectedChip: 10- -0.7487999916,-3.9935998916,-0.1559999942

Am I doing something wrong? Or am I thinking wrong? Do you think the sensor is working correctly? I mean even if my code would be wrong, it should be wrong for both sensors, shouldn't it.


I'll also add the code here, but it's mostly the Sparkfun sample code:

//Add the SPI library so we can communicate with the ADXL345 sensor
#include <SPI.h>

//Assign the Chip Select signal to pin 10.
//int CS=10;
int CS_1=10;
int CS_2=9;

//ADXL345 Register Addresses
#define DEVID   0x00  //Device ID Register
#define THRESH_TAP  0x1D  //Tap Threshold
#define OFSX    0x1E  //X-axis offset
#define OFSY    0x1F  //Y-axis offset
#define OFSZ    0x20  //Z-axis offset
#define DURATION  0x21  //Tap Duration
#define LATENT    0x22  //Tap latency
#define WINDOW    0x23  //Tap window
#define THRESH_ACT  0x24  //Activity Threshold
#define THRESH_INACT  0x25  //Inactivity Threshold
#define TIME_INACT  0x26  //Inactivity Time
#define ACT_INACT_CTL 0x27  //Axis enable control for activity and inactivity detection
#define THRESH_FF 0x28  //free-fall threshold
#define TIME_FF   0x29  //Free-Fall Time
#define TAP_AXES  0x2A  //Axis control for tap/double tap
#define ACT_TAP_STATUS  0x2B  //Source of tap/double tap
#define BW_RATE   0x2C  //Data rate and power mode control
#define POWER_CTL 0x2D  //Power Control Register
#define INT_ENABLE  0x2E  //Interrupt Enable Control
#define INT_MAP   0x2F  //Interrupt Mapping Control
#define INT_SOURCE  0x30  //Source of interrupts
#define DATA_FORMAT 0x31  //Data format control
#define DATAX0    0x32  //X-Axis Data 0
#define DATAX1    0x33  //X-Axis Data 1
#define DATAY0    0x34  //Y-Axis Data 0
#define DATAY1    0x35  //Y-Axis Data 1
#define DATAZ0    0x36  //Z-Axis Data 0
#define DATAZ1    0x37  //Z-Axis Data 1
#define FIFO_CTL  0x38  //FIFO control
#define FIFO_STATUS 0x39  //FIFO status



//This buffer will hold values read from the ADXL345 registers.
char values[10];
//These variables will be used to hold the x,y and z axis accelerometer values.
int x,y,z;
double xg, yg, zg;

//Convert the accelerometer value to G's. 
//With 10 bits measuring over a +/-4g range we can find how to convert by using the equation:
// Gs = Measurement Value * (G-range/(2^10)) or Gs = Measurement Value * (8/1024)
float gMultiplyer = (8/(2^10));

void setup(){ 
  //Initiate an SPI communication instance.
  SPI.begin();
  //Configure the SPI connection for the ADXL345.
  SPI.setDataMode(SPI_MODE3);
  //Create a serial connection to display the data on the terminal.
  Serial.begin(9600);
  
  //Set up the Chip Select pin to be an output from the Arduino.
  pinMode(CS_1, OUTPUT);
  pinMode(CS_2, OUTPUT);
  //Before communication starts, the Chip Select pin needs to be set high.
  digitalWrite(CS_1, HIGH);
  digitalWrite(CS_2, HIGH);
  
  //Put the ADXL345 into +/- 4G range by writing the value 0x01 to the DATA_FORMAT register.
  writeRegister(DATA_FORMAT, 0x01, CS_1);
  writeRegister(DATA_FORMAT, 0x01, CS_2);
  //Put the ADXL345 into Measurement Mode by writing 0x08 to the POWER_CTL register.
  writeRegister(POWER_CTL, 0x08, CS_1);  //Measurement mode  
  writeRegister(POWER_CTL, 0x08, CS_2);  //Measurement mode  

  delay(1000);
}

void loop(){
  printValuesFor(CS_1, HIGH);
  printValuesFor(CS_2, HIGH);
  delay(10); 
}

void printValuesFor(int selectedChip, boolean printG){
    //Reading 6 bytes of data starting at register DATAX0 will retrieve the x,y and z acceleration values from the ADXL345.
  //The results of the read operation will get stored to the values[] buffer.
  readRegister(DATAX0, 6, values, selectedChip);

  //The ADXL345 gives 10-bit acceleration values, but they are stored as bytes (8-bits). To get the full value, two bytes must be combined for each axis.
  //The X value is stored in values[0] and values[1].
  x = ((int)values[1]<<8)|(int)values[0];
  //The Y value is stored in values[2] and values[3].
  y = ((int)values[3]<<8)|(int)values[2];
  //The Z value is stored in values[4] and values[5].
  z = ((int)values[5]<<8)|(int)values[4];
  
  //Convert the accelerometer value to G's. 
  //With 10 bits measuring over a +/-4g range we can find how to convert by using the equation:
  // Gs = Measurement Value * (G-range/(2^10)) or Gs = Measurement Value * (8/1024)
  xg = x * 0.0078;
  yg = y * 0.0078;
  zg = z * 0.0078;
  
  //Print the results to the terminal.
  Serial.print("SelectedChip: ");
  Serial.print(selectedChip, DEC);
  Serial.print("- ");
  if(printG){
    Serial.print(xg, DEC);
    Serial.print(',');
    Serial.print(yg, DEC);
    Serial.print(',');
    Serial.println(zg, DEC);    
  }else{
    Serial.print(x, DEC);
    Serial.print(',');
    Serial.print(y, DEC);
    Serial.print(',');
    Serial.println(z, DEC);    
  }
}

//This function will write a value to a register on the ADXL345.
//Parameters:
//  char registerAddress - The register to write a value to
//  char value - The value to be written to the specified register.
void writeRegister(char registerAddress, char value, int selectedChip){
  //Set Chip Select pin low to signal the beginning of an SPI packet.
  digitalWrite(selectedChip, LOW);
  //Transfer the register address over SPI.
  SPI.transfer(registerAddress);
  //Transfer the desired register value over SPI.
  SPI.transfer(value);
  //Set the Chip Select pin high to signal the end of an SPI packet.
  digitalWrite(selectedChip, HIGH);
}

//This function will read a certain number of registers starting from a specified address and store their values in a buffer.
//Parameters:
//  char registerAddress - The register addresse to start the read sequence from.
//  int numBytes - The number of registers that should be read.
//  char * values - A pointer to a buffer where the results of the operation should be stored.
void readRegister(char registerAddress, int numBytes, char * values, int selectedChip){
  //Since we're performing a read operation, the most significant bit of the register address should be set.
  char address = 0x80 | registerAddress;
  //If we're doing a multi-byte read, bit 6 needs to be set as well.
  if(numBytes > 1)address = address | 0x40;
  
  //Set the Chip select pin low to start an SPI packet.
  digitalWrite(selectedChip, LOW);
  //Transfer the starting register address that needs to be read.
  SPI.transfer(address);
  //Continue to read registers until we've read the number specified, storing the results to the input buffer.
  for(int i=0; i<numBytes; i++){
    values[i] = SPI.transfer(0x00);
  }
  //Set the Chips Select pin high to end the SPI packet.
  digitalWrite(selectedChip, HIGH);
}

Best Answer

Ok, I found the issue. The gy-291s, that I bought seem to be completely uncalibrated. I used them with a +-4g range. But especially the z-axis is oftimes off by about 8g. Therefore, the measures were completely weird. I also switched to the adafruit library, since it seems to be the better solution compared to the sparkfun code. The lib can be found here: https://github.com/adafruit/Adafruit_ADXL345/.

Hope this helps anybody with the same issue.