ADXL345 with Python and the Raspberry Pi

General project help for Adafruit customers

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
User avatar
static
 
Posts: 188
Joined: Thu Dec 23, 2010 6:21 pm

ADXL345 with Python and the Raspberry Pi

Post by static »

Edit: I'm going to try to keep the code at the end of THIS post updated to the most current version I am working with. That will keep people from having to scan through the comments.

I'm working on building an I2C library for the ADXL345.

I'm stuck. I'm trying to figure out the two's-complement math the the accelerometer uses to report accelerations in the three axes.

The long and the short of the problem is here:
Each axis reports to two 8-bit registers. The lower register is the "low byte register" (X0, Y0, Z0 below). The higher register is the "high byte register" (X1, Y1, Z1 below). The first couple of bits in the higher register determine the "sign" of the overall value.

When the system is in 13-bit mode, the upper four bits are "sign bits". If there is a "1" there, the value is negative.

The code below does not take this into account. It is returning signed-16bit values just to look for changes in the ADXL345 state.

I'm plugging away at this, but I'm not having much luck. I've been spinning on the same problem for several hours.
Here's the quick start sheet:
http://www.analog.com/static/imported-f ... N-1077.pdf
It states the problem succinctly on page 4.

Code: Select all

#!/usr/bin/python
# coding=<UTF-8> 

import time
from Adafruit_I2C import Adafruit_I2C

# ===========================================================================
# ADXL345 Class, written for Python 3.x Modified 4-20-13 by Static
# This is definitely a work in progress.  This code relies on the
# Adafruit_I2C.py code.  Please support the open source movement, and those
# dedicated to open source.  www.adafruit.com
# If you find this code useful or have suggestions, hit me up at:
# medicforlife.blogspot.com
# As it stands, the code isn't commented out.  A ton of revision needs to happen
# The end goal of this code is to spit out acceleration readings on demand.
# Due to the constraints of the ADXL345, this will always be three readings, X,Y,Z
# ===========================================================================

class ADXL345 :
  i2c = None

  # Registers
  __ADXL345_DEVID = 0x00
  __ADXL345_THRESH_TAP = 0x1D	  #8 bits
  __ADXL345_X_OFFSET = 0x1E	  #8 bits
  __ADXL345_Y_OFFSET = 0x1F	  #8 bits
  __ADXL345_Z_OFFSET = 0x20	  #8 bits
  __ADXL345_TAP_DUR = 0x21	  #8 bits
  __ADXL345_TAP_LATENCY = 0x22	  #8 bits
  __ADXL345_TAP_WINDOW = 0x23	  #8 bits
  __ADXL345_THRESH_ACT = 0x24	  #8 bits
  __ADXL345_THRESH_INACT = 0x25	  #8 bits
  __ADXL345_TIME_INACT = 0x26	  #8 bits
  __ADXL345_ACT_INACT_CTL = 0x27
  __ADXL345_THRESH_FF = 0x28	  #8 bits
  __ADXL345_TIME_FF = 0x29	  #8 bits
  __ADXL345_TAP_AXES = 0x2A	  
  __ADXL345_ACT_TAP_STATUS = 0x2B
  __ADXL345_BW_RATE = 0x2C
  __ADXL345_PWR_CTL = 0x2D
  __ADXL345_INT_ENABLE = 0x2E
  __ADXL345_INT_MAP = 0x2F
  __ADXL345_INT_SOURCE = 0x30
  __ADXL345_DATA_FORMAT = 0x31
  __ADXL345_DATA_X0 = 0x32	  #8 bits
  __ADXL345_DATA_X1 = 0x33	  #8 bits
  __ADXL345_DATA_Y0 = 0x34	  #8 bits
  __ADXL345_DATA_Y1 = 0x35	  #8 bits
  __ADXL345_DATA_Z0 = 0x36	  #8 bits
  __ADXL345_DATA_Z1 = 0x37	  #8 bits
  __ADXL345_FIFO_CTL = 0x38
  __ADXL345_FIFO_STATUS = 0x39

  # Datarate controls using BW_RATE register 0x2c
  __ADXL345_DR_3200 = 0b00001111
  __ADXL345_DR_1600 = 0b00001110
  __ADXL345_DR_800 = 0b00001101
  __ADXL345_DR_400 = 0b00001100
  __ADXL345_DR_200 = 0b00001011
  __ADXL345_DR_100 = 0b00001010
  __ADXL345_DR_50 = 0b00001001
  __ADXL345_DR_25 = 0b00001000
  __ADXL345_DR_12_5 = 0b00000111
  __ADXL345_DR_6_25 = 0b00000110

  # Datarate controls using BW_RATE at low power
  __ADXL345_DR_400 = 0b00011100
  __ADXL345_DR_200 = 0b00011011
  __ADXL345_DR_100 = 0b00011010
  __ADXL345_DR_50 = 0b00011001
  __ADXL345_DR_25 = 0b00011000
  __ADXL345_DR_12_5 = 0b00010111

  # Data Format using DATA_FORMAT 0x31
  __ADXL345_SELFTEST =    0b10000000
  __ADXL345_SPI_BIT =     0b01000000
  __ADXL345_INT_INVERT =  0b00100000
  __ADXL345_FULL_RES =    0b00001000
  __ADXL345_JUSTIFY =     0b00000100
  __ADXL345_2G =          0b00000000
  __ADXL345_4G =          0b00000001
  __ADXL345_8G =          0b00000010
  __ADXL345_16G =         0b00000011

  # FIFO Control using FIFO_CTL 0x38
  __ADXL345_BYPASS =      0b00000000
  __ADXL345_FIFO =        0b01000000
  __ADXL345_STREAM =      0b10000000
  __ADXL345_TRIG_MODE =   0b11000000
  __ADXL345_TRIG_INT1 =   0b00000000
  __ADXL345_TRIG_INT2 =   0b00100000
  __ADXL345_SAMPLES31 =   0b00011111
  __ADXL345_SAMPLES16 =   0b00010000
  __ADXL345_SAMPLES10 =   0b00001010

  # Power control using PWR_CTL 0x2D
  __ADXL345_LINK_BIT    = 0b00100000
  __ADXL345_AUTO_SLEEP  = 0b00010000
  __ADXL345_MEASURE     = 0b00001000
  __ADXL345_STANDBY     = 0b00000000
  __ADXL345_SLEEP       = 0b00000100
  __ADXL345_WAKEUP8HZ   = 0b00000000
  __ADXL345_WAKEUP4HZ   = 0b00000001
  __ADXL345_WAKEUP2HZ   = 0b00000010
  __ADXL345_WAKEUP1HZ   = 0b00000011
  

  


  # Constructor
  def __init__(self, address = 0x53, busnum = -1, debug = False):
    self.i2c = Adafruit_I2C(address, busnum, debug)
    self.address = address
    self.debug = debug
    if address == 0x53:
      self.__ADXL345_WRITE = 0xA6
      self.__ADXL345_READ = 0xA7
    elif address == 0x1D:
      self.__ADXL345_WRITE = 0x3A
      self.__ADXL345_READ = 0x3B
    else:
      if self.debug == True:
        print("Invalid I2C Address for ADXL345: ", self.address)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY) 
    self.i2c.write8(self.__ADXL345_BW_RATE, self.__ADXL345_DR_100)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, (self.__ADXL345_2G + self.__ADXL345_FULL_RES))
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)

  def gravTest(self):
    interval = 0.1
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, self.__ADXL345_2G)
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE)
    time.sleep(interval)
    print("2G self test values X,Y,Z",self.readAccel(0.0043))
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, self.__ADXL345_4G)
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE)
    time.sleep(interval)
    print("4G self test values X,Y,Z",self.readAccel((0.0043*2)))
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, self.__ADXL345_8G)
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE)
    time.sleep(interval)
    print("8G self test values X,Y,Z",self.readAccel((0.0043*4)))
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, self.__ADXL345_16G)
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE)
    time.sleep(interval)
    print("16G self test values X,Y,Z",self.readAccel((0.0043*8)))

  def quickCalibrate(self, cycles):
    i = 0
    x,y,z,xrun,yrun,zrun,xavg,yavg,zavg = 0,0,0,0,0,0,0,0,0
    for i in range(cycles):
      x,y,z = self.readAccel(0.0043)
      xrun = xrun+x
      yrun = yrun+y
      zrun = zrun+z
    xavg = xrun/cycles
    yavg = yrun/cycles
    zavg = zrun/cycles
    print(xavg,yavg,zavg)
    
    



  def readAccel(self, ScaleFactor):
    #ScaleFactor = 0.0043
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE)
    #time.sleep(0.0005)
    X = (self.i2c.readS16(self.__ADXL345_DATA_X0)) * ScaleFactor
    Y = (self.i2c.readS16(self.__ADXL345_DATA_Y0)) * ScaleFactor
    Z = (self.i2c.readS16(self.__ADXL345_DATA_Z0)) * ScaleFactor
    #X = (self.i2c.reverseByteOrder(self.i2c.readS16(self.__ADXL345_DATA_X0))) * ScaleFactor
    #Y = (self.i2c.reverseByteOrder(self.i2c.readS16(self.__ADXL345_DATA_Y0))) * ScaleFactor
    #Z = (self.i2c.reverseByteOrder(self.i2c.readS16(self.__ADXL345_DATA_Z0))) * ScaleFactor
    if self.debug == True:
      print("X0 = ", X0)
    return X,Y,Z
  
    

Current version of code:

Code: Select all

#!/usr/bin/python
# coding=<UTF-8> 

import time
from Adafruit_I2C import Adafruit_I2C

# ===========================================================================
# ADXL345 Class, written for Python 3.x Modified 5-3-13 by Static
# This is definitely a work in progress.  This code relies on the
# Adafruit_I2C.py code.  Please support the open source movement, and those
# dedicated to open source.  www.adafruit.com
# If you find this code useful or have suggestions, hit me up at:
# medicforlife.blogspot.com
# As it stands, the code isn't commented out.  A ton of revision still needs to happen
# The end goal of this code is to spit out acceleration readings on demand.
# Due to the constraints of the ADXL345, this will always be three readings, X,Y,Z
# Thanks to tldr for making me do the math correctly.
# ===========================================================================

class ADXL345 :
  i2c = None

  # Registers
  __ADXL345_DEVID = 0x00
  __ADXL345_THRESH_TAP = 0x1D	  #8 bits
  __ADXL345_X_OFFSET = 0x1E	  #8 bits
  __ADXL345_Y_OFFSET = 0x1F	  #8 bits
  __ADXL345_Z_OFFSET = 0x20	  #8 bits
  __ADXL345_TAP_DUR = 0x21	  #8 bits
  __ADXL345_TAP_LATENCY = 0x22	  #8 bits
  __ADXL345_TAP_WINDOW = 0x23	  #8 bits
  __ADXL345_THRESH_ACT = 0x24	  #8 bits
  __ADXL345_THRESH_INACT = 0x25	  #8 bits
  __ADXL345_TIME_INACT = 0x26	  #8 bits
  __ADXL345_ACT_INACT_CTL = 0x27
  __ADXL345_THRESH_FF = 0x28	  #8 bits
  __ADXL345_TIME_FF = 0x29	  #8 bits
  __ADXL345_TAP_AXES = 0x2A	  
  __ADXL345_ACT_TAP_STATUS = 0x2B
  __ADXL345_BW_RATE = 0x2C
  __ADXL345_PWR_CTL = 0x2D
  __ADXL345_INT_ENABLE = 0x2E
  __ADXL345_INT_MAP = 0x2F
  __ADXL345_INT_SOURCE = 0x30
  __ADXL345_DATA_FORMAT = 0x31
  __ADXL345_DATA_X0 = 0x32	  #8 bits
  __ADXL345_DATA_X1 = 0x33	  #8 bits
  __ADXL345_DATA_Y0 = 0x34	  #8 bits
  __ADXL345_DATA_Y1 = 0x35	  #8 bits
  __ADXL345_DATA_Z0 = 0x36	  #8 bits
  __ADXL345_DATA_Z1 = 0x37	  #8 bits
  __ADXL345_FIFO_CTL = 0x38
  __ADXL345_FIFO_STATUS = 0x39

  # Datarate controls using BW_RATE register 0x2c
  __ADXL345_DR_3200 = 0b00001111
  __ADXL345_DR_1600 = 0b00001110
  __ADXL345_DR_800 = 0b00001101
  __ADXL345_DR_400 = 0b00001100
  __ADXL345_DR_200 = 0b00001011
  __ADXL345_DR_100 = 0b00001010
  __ADXL345_DR_50 = 0b00001001
  __ADXL345_DR_25 = 0b00001000
  __ADXL345_DR_12_5 = 0b00000111
  __ADXL345_DR_6_25 = 0b00000110

  # Datarate controls using BW_RATE at low power
  __ADXL345_DR_400 = 0b00011100
  __ADXL345_DR_200 = 0b00011011
  __ADXL345_DR_100 = 0b00011010
  __ADXL345_DR_50 = 0b00011001
  __ADXL345_DR_25 = 0b00011000
  __ADXL345_DR_12_5 = 0b00010111

  # Data Format using DATA_FORMAT 0x31
  __ADXL345_SELFTEST =    0b10000000
  __ADXL345_SPI_BIT =     0b01000000
  __ADXL345_INT_INVERT =  0b00100000
  __ADXL345_FULL_RES =    0b00001000
  __ADXL345_JUSTIFY =     0b00000100
  __ADXL345_2G =          0b00000000
  __ADXL345_4G =          0b00000001
  __ADXL345_8G =          0b00000010
  __ADXL345_16G =         0b00000011

  # FIFO Control using FIFO_CTL 0x38
  __ADXL345_BYPASS =      0b00000000
  __ADXL345_FIFO =        0b01000000
  __ADXL345_STREAM =      0b10000000
  __ADXL345_TRIG_MODE =   0b11000000
  __ADXL345_TRIG_INT1 =   0b00000000
  __ADXL345_TRIG_INT2 =   0b00100000
  __ADXL345_SAMPLES31 =   0b00011111
  __ADXL345_SAMPLES16 =   0b00010000
  __ADXL345_SAMPLES10 =   0b00001010

  # Power control using PWR_CTL 0x2D
  __ADXL345_LINK_BIT    = 0b00100000
  __ADXL345_AUTO_SLEEP  = 0b00010000
  __ADXL345_MEASURE     = 0b00001000
  __ADXL345_STANDBY     = 0b00000000
  __ADXL345_SLEEP       = 0b00000100
  __ADXL345_WAKEUP8HZ   = 0b00000000
  __ADXL345_WAKEUP4HZ   = 0b00000001
  __ADXL345_WAKEUP2HZ   = 0b00000010
  __ADXL345_WAKEUP1HZ   = 0b00000011
  

  


  # Constructor
  def __init__(self, address = 0x53, busnum = -1, debug = False):
    self.i2c = Adafruit_I2C(address, busnum, debug)
    self.address = address
    self.debug = debug
    self.xcal = False
    self.ycal = False
    self.zcal = False
    if address == 0x53:
      self.__ADXL345_WRITE = 0xA6
      self.__ADXL345_READ = 0xA7
    elif address == 0x1D:
      self.__ADXL345_WRITE = 0x3A
      self.__ADXL345_READ = 0x3B
    else:
      if self.debug == True:
        print("Invalid I2C Address for ADXL345: ", self.address)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY) 
    self.i2c.write8(self.__ADXL345_BW_RATE, self.__ADXL345_DR_100)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, (self.__ADXL345_2G + self.__ADXL345_FULL_RES))
    self.gScale = 2
    self.scale = 0.043
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)

  def setgScale2(self):
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, (self.__ADXL345_2G + self.__ADXL345_FULL_RES))
    self.gscale = 2
    self.scale = 0.043

  def setgScale4(self):
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, (self.__ADXL345_4G + self.__ADXL345_FULL_RES))
    self.gscale = 4
    self.scale = 2 * 0.043

  def setgScale8(self):
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, (self.__ADXL345_8G + self.__ADXL345_FULL_RES))
    self.gscale = 8
    self.scale = 4 * 0.043

  def setgScale16(self):
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, (self.__ADXL345_16G + self.__ADXL345_FULL_RES))
    self.gscale = 16
    self.scale = 8 * 0.043

  def getgScale(self):
    return self.gscale
  def getScale(self):
    return self.scale

  def gravTest(self):
    interval = 0.1
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, self.__ADXL345_2G)
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE)
    time.sleep(interval)
    print("2G self test values X,Y,Z",self.scaledAccel(0.0043))
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, self.__ADXL345_4G)
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE)
    time.sleep(interval)
    print("4G self test values X,Y,Z",self.scaledAccel((0.0043*2)))
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, self.__ADXL345_8G)
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE)
    time.sleep(interval)
    print("8G self test values X,Y,Z",self.scaledAccel((0.0043*4)))
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, self.__ADXL345_16G)
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE)
    time.sleep(interval)
    print("16G self test values X,Y,Z",self.scaledAccel((0.0043*8)))

  def quickCalibrate(self, cycles = 100):
    i = 0
    x,y,z,xrun,yrun,zrun,xavg,yavg,zavg = 0,0,0,0,0,0,0,0,0
    for i in range(cycles):
      x,y,z = self.readAccel()
      xrun = xrun+x
      yrun = yrun+y
      zrun = zrun+z
    xavg = xrun/cycles
    yavg = yrun/cycles
    zavg = zrun/cycles
    if self.debug == True:
      print(xavg,yavg,zavg)
    self.xcal = xavg
    self.ycal = yavg
    self.zcal = zavg
    #return self.xcal, self.ycal, self.zcal



  def readAccelCal(self):
    if self.xcal == False or self.ycal == False or self.zcal == False:
      self.quickCalibrate()
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE) # Set power control to measure
    x0 = self.i2c.readU8(self.__ADXL345_DATA_X0)                    # Read X-Axis 0
    x1 = self.i2c.readU8(self.__ADXL345_DATA_X1)                    # Read X-Axis 1
    X = x0 + (x1 << 8)                                              # By default, add the two together (bit-shift x1)
    if (x1 > 15):                                                   # if x1 signifies a negative
      x1 = (x1 & 0b1111)                                            # don't count the first 4 bits
      X = (x0 + (x1 << 8))+1                                        # bit shift and add to x0, then add 1
      X = -X                                                        # then multiply by -1 (make this a negative value)
      
    y0 = self.i2c.readU8(self.__ADXL345_DATA_Y0)
    y1 = self.i2c.readU8(self.__ADXL345_DATA_Y1)
    Y = y0 + (y1 << 8)
    if (y1 > 15):
      y1 = (y1 & 0b1111)
      Y = (y0 + (y1 << 8))+1
      Y = -Y
    
    z0 = self.i2c.readU8(self.__ADXL345_DATA_Z0)
    z1 = self.i2c.readU8(self.__ADXL345_DATA_Z1)
    Z = z0 + (z1 << 8)
    if (z1 > 15):
      z1 = (z1 & 0b1111)
      Z = (z0 + (z1 << 8))+1
      Z = -Z
    
    if self.debug == True:
      print(X - self.xcal, Y - self.ycal, Z - self.zcal)
    return X - self.xcal, Y - self.ycal, Z - self.zcal              # subtract the quick calibrate average values and return

  def scaledAccel(self, ScaleFactor):
    x,y,z = self.readAccel()
    x = x * ScaleFactor
    y = y * ScaleFactor
    z = z * ScaleFactor
    return x,y,z

  def scaledAccelCal(self, ScaleFactor):
    x,y,z = self.readAccelCal()
    x = x * ScaleFactor
    y = y * ScaleFactor
    z = z * ScaleFactor
    return x,y,z
    

    



  def readAccel(self):
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE) # Set power control to measure
    x0 = self.i2c.readU8(self.__ADXL345_DATA_X0)                    # Read X-Axis 0
    x1 = self.i2c.readU8(self.__ADXL345_DATA_X1)                    # Read X-Axis 1
    X = x0 + (x1 << 8)                                              # By default, add the two together (bit-shift x1)
    if (x1 > 15):                                                   # if x1 signifies a negative
      x1 = (x1 & 0b1111)                                            # don't count the first 4 bits
      X = (x0 + (x1 << 8))+1                                        # bit shift and add to x0, then add 1
      X = -X                                                        # then multiply by -1 (make this a negative value)
      
    y0 = self.i2c.readU8(self.__ADXL345_DATA_Y0)
    y1 = self.i2c.readU8(self.__ADXL345_DATA_Y1)
    Y = y0 + (y1 << 8)
    if (y1 > 15):
      y1 = (y1 & 0b1111)
      Y = (y0 + (y1 << 8))+1
      Y = -Y
    
    z0 = self.i2c.readU8(self.__ADXL345_DATA_Z0)
    z1 = self.i2c.readU8(self.__ADXL345_DATA_Z1)
    Z = z0 + (z1 << 8)
    if (z1 > 15):
      z1 = (z1 & 0b1111)
      Z = (z0 + (z1 << 8))+1
      Z = -Z
    
    if self.debug == True:
      print(X,Y,Z)
    return X,Y,Z

  def scaledAccel(self, ScaleFactor):
    x,y,z = self.readAccel()
    x = x * ScaleFactor
    y = y * ScaleFactor
    z = z * ScaleFactor
    return x,y,z
    

Last edited by static on Fri May 03, 2013 4:44 pm, edited 2 times in total.

tldr
 
Posts: 466
Joined: Thu Aug 30, 2012 1:34 am

Re: ADXL345 with Python and the Raspberry Pi

Post by tldr »

how about something along the lines of

Code: Select all

    if (foo & 0x8000) foo |= 0xffff0000;
oops. that's c.

Code: Select all

  if (foo & 0x8000) :
    foo = (~foo + 1) & 0xffff
~foo + 1 is the two's complement of foo. masking with 0xffff, (65,535) will get rid of any overflow out of the high order bit.

User avatar
static
 
Posts: 188
Joined: Thu Dec 23, 2010 6:21 pm

Re: ADXL345 with Python and the Raspberry Pi

Post by static »

I did it a little differently, but the results seem to look good.
The idea was to take two 8-bit numbers from the ADXL345 output and have them give a range between 4095 and -4095.
Here was my test code to prove that it would work:

Code: Select all

x0 = int(input("First Value"))
x1 = int(input("Second Value"))

if x1 > 15:
  x1 = (((x1) & 0b1111))
  print("Subtotal x1 ",x1)
  x = ((x0) + (x1<<8))*-1
  print("Subtotal x ", x)
else:
  x= (x0) + (x1<<8)
print(x)
print(bin(x))

tldr, thanks for point out the direction to go. I would have avoided bitwise operations if I could (I've always found them confusing and counter-intuitive). As it was, it still took significant work.

Here's the new code below. The relevant sections are commented.
It looks like my "indoor" sensor has an issue. I'm getting really noisy readings. My outdoor sensor is very stable.

Code: Select all

#!/usr/bin/python
# coding=<UTF-8> 

import time
from Adafruit_I2C import Adafruit_I2C

# ===========================================================================
# ADXL345 Class, written for Python 3.x Modified 4-21-13 by Static
# This is definitely a work in progress.  This code relies on the
# Adafruit_I2C.py code.  Please support the open source movement, and those
# dedicated to open source.  www.adafruit.com
# If you find this code useful or have suggestions, hit me up at:
# medicforlife.blogspot.com
# As it stands, the code isn't commented out.  A ton of revision needs to happen
# The end goal of this code is to spit out acceleration readings on demand.
# Due to the constraints of the ADXL345, this will always be three readings, X,Y,Z
# ===========================================================================

class ADXL345 :
  i2c = None

  # Registers
  __ADXL345_DEVID = 0x00
  __ADXL345_THRESH_TAP = 0x1D	  #8 bits
  __ADXL345_X_OFFSET = 0x1E	  #8 bits
  __ADXL345_Y_OFFSET = 0x1F	  #8 bits
  __ADXL345_Z_OFFSET = 0x20	  #8 bits
  __ADXL345_TAP_DUR = 0x21	  #8 bits
  __ADXL345_TAP_LATENCY = 0x22	  #8 bits
  __ADXL345_TAP_WINDOW = 0x23	  #8 bits
  __ADXL345_THRESH_ACT = 0x24	  #8 bits
  __ADXL345_THRESH_INACT = 0x25	  #8 bits
  __ADXL345_TIME_INACT = 0x26	  #8 bits
  __ADXL345_ACT_INACT_CTL = 0x27
  __ADXL345_THRESH_FF = 0x28	  #8 bits
  __ADXL345_TIME_FF = 0x29	  #8 bits
  __ADXL345_TAP_AXES = 0x2A	  
  __ADXL345_ACT_TAP_STATUS = 0x2B
  __ADXL345_BW_RATE = 0x2C
  __ADXL345_PWR_CTL = 0x2D
  __ADXL345_INT_ENABLE = 0x2E
  __ADXL345_INT_MAP = 0x2F
  __ADXL345_INT_SOURCE = 0x30
  __ADXL345_DATA_FORMAT = 0x31
  __ADXL345_DATA_X0 = 0x32	  #8 bits
  __ADXL345_DATA_X1 = 0x33	  #8 bits
  __ADXL345_DATA_Y0 = 0x34	  #8 bits
  __ADXL345_DATA_Y1 = 0x35	  #8 bits
  __ADXL345_DATA_Z0 = 0x36	  #8 bits
  __ADXL345_DATA_Z1 = 0x37	  #8 bits
  __ADXL345_FIFO_CTL = 0x38
  __ADXL345_FIFO_STATUS = 0x39

  # Datarate controls using BW_RATE register 0x2c
  __ADXL345_DR_3200 = 0b00001111
  __ADXL345_DR_1600 = 0b00001110
  __ADXL345_DR_800 = 0b00001101
  __ADXL345_DR_400 = 0b00001100
  __ADXL345_DR_200 = 0b00001011
  __ADXL345_DR_100 = 0b00001010
  __ADXL345_DR_50 = 0b00001001
  __ADXL345_DR_25 = 0b00001000
  __ADXL345_DR_12_5 = 0b00000111
  __ADXL345_DR_6_25 = 0b00000110

  # Datarate controls using BW_RATE at low power
  __ADXL345_DR_400 = 0b00011100
  __ADXL345_DR_200 = 0b00011011
  __ADXL345_DR_100 = 0b00011010
  __ADXL345_DR_50 = 0b00011001
  __ADXL345_DR_25 = 0b00011000
  __ADXL345_DR_12_5 = 0b00010111

  # Data Format using DATA_FORMAT 0x31
  __ADXL345_SELFTEST =    0b10000000
  __ADXL345_SPI_BIT =     0b01000000
  __ADXL345_INT_INVERT =  0b00100000
  __ADXL345_FULL_RES =    0b00001000
  __ADXL345_JUSTIFY =     0b00000100
  __ADXL345_2G =          0b00000000
  __ADXL345_4G =          0b00000001
  __ADXL345_8G =          0b00000010
  __ADXL345_16G =         0b00000011

  # FIFO Control using FIFO_CTL 0x38
  __ADXL345_BYPASS =      0b00000000
  __ADXL345_FIFO =        0b01000000
  __ADXL345_STREAM =      0b10000000
  __ADXL345_TRIG_MODE =   0b11000000
  __ADXL345_TRIG_INT1 =   0b00000000
  __ADXL345_TRIG_INT2 =   0b00100000
  __ADXL345_SAMPLES31 =   0b00011111
  __ADXL345_SAMPLES16 =   0b00010000
  __ADXL345_SAMPLES10 =   0b00001010

  # Power control using PWR_CTL 0x2D
  __ADXL345_LINK_BIT    = 0b00100000
  __ADXL345_AUTO_SLEEP  = 0b00010000
  __ADXL345_MEASURE     = 0b00001000
  __ADXL345_STANDBY     = 0b00000000
  __ADXL345_SLEEP       = 0b00000100
  __ADXL345_WAKEUP8HZ   = 0b00000000
  __ADXL345_WAKEUP4HZ   = 0b00000001
  __ADXL345_WAKEUP2HZ   = 0b00000010
  __ADXL345_WAKEUP1HZ   = 0b00000011
  

  


  # Constructor
  def __init__(self, address = 0x53, busnum = -1, debug = False):
    self.i2c = Adafruit_I2C(address, busnum, debug)
    self.address = address
    self.debug = debug
    if address == 0x53:
      self.__ADXL345_WRITE = 0xA6
      self.__ADXL345_READ = 0xA7
    elif address == 0x1D:
      self.__ADXL345_WRITE = 0x3A
      self.__ADXL345_READ = 0x3B
    else:
      if self.debug == True:
        print("Invalid I2C Address for ADXL345: ", self.address)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY) 
    self.i2c.write8(self.__ADXL345_BW_RATE, self.__ADXL345_DR_100)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, (self.__ADXL345_2G + self.__ADXL345_FULL_RES))
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)

  def gravTest(self):
    interval = 0.1
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, self.__ADXL345_2G)
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE)
    time.sleep(interval)
    print("2G self test values X,Y,Z",self.readAccel(0.0043))
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, self.__ADXL345_4G)
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE)
    time.sleep(interval)
    print("4G self test values X,Y,Z",self.readAccel((0.0043*2)))
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, self.__ADXL345_8G)
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE)
    time.sleep(interval)
    print("8G self test values X,Y,Z",self.readAccel((0.0043*4)))
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, self.__ADXL345_16G)
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE)
    time.sleep(interval)
    print("16G self test values X,Y,Z",self.readAccel((0.0043*8)))

  def quickCalibrate(self, cycles):
    i = 0
    x,y,z,xrun,yrun,zrun,xavg,yavg,zavg = 0,0,0,0,0,0,0,0,0
    for i in range(cycles):
      x,y,z = self.readAccel(0.0043)
      xrun = xrun+x
      yrun = yrun+y
      zrun = zrun+z
    xavg = xrun/cycles
    yavg = yrun/cycles
    zavg = zrun/cycles
    print(xavg,yavg,zavg)
    
    



  def readAccel(self):
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE) # Set power control to measure
    x0 = self.i2c.readU8(self.__ADXL345_DATA_X0)                    # Read X-Axis 0
    x1 = self.i2c.readU8(self.__ADXL345_DATA_X1)                    # Read X-Axis 1
    if (x1 > 15):                                                   # if x1 signifies a negative
      x1 = (x1 & 0b1111)                                            # don't count the first 4 bits
      X = -1*((x0) + (x1<<8))                                       # bit shift and add to x0
    else:                                                           # otherwise
      X = (x0) + (x1<<8)                                            # just bit shift and add to x0
      
    y0 = self.i2c.readU8(self.__ADXL345_DATA_Y0)
    y1 = self.i2c.readU8(self.__ADXL345_DATA_Y1)
    if (y1 > 15):
      y1 = (y1 & 0b1111)
      Y = -1*((y0) + (y1<<8))
    else:
      Y = (y0) + (y1<<8)
    z0 = self.i2c.readU8(self.__ADXL345_DATA_Z0)
    z1 = self.i2c.readU8(self.__ADXL345_DATA_Z1)
    if (z1 > 15):
      z1 = (z1 & 0b1111)
      Z = -1*((z0) + (z1<<8))
    else:
      Z = (z0) + (z1<<8)
    if self.debug == True:
      print(X,Y,Z)
    return X,Y,Z

  def scaledAccel(self, ScaleFactor):
    x,y,z = self.readAccel()
    x = x * ScaleFactor
    y = y * ScaleFactor
    z = z * ScaleFactor
    return x,y,z
    

Thanks again. I'm still going to work on improving the code. Lots of options and toggles to play with.

tldr
 
Posts: 466
Joined: Thu Aug 30, 2012 1:34 am

Re: ADXL345 with Python and the Raspberry Pi

Post by tldr »

Code: Select all

    if (x1 > 15):                                                   # if x1 signifies a negative
      x1 = (x1 & 0b1111)                                            # don't count the first 4 bits
      X = -1*((x0) + (x1<<8))                                       # bit shift and add to x0
    else:                                                           # otherwise
      X = (x0) + (x1<<8)                                            # just bit shift and add to x0
let's say the accelerometer returns a value of -1. x1 and x0 will both be 0xff.

x1 & 0x0f will give the result 0xff & 0x0f, or 0xf.

x0 + (x1 << 8) will give the result 0x0fff, which is 4095.

(seems to me one used to be able to turn off the f*cking smilies.) 8(

multiply that by -1 and your result is -4095.

Code: Select all

$ python
Python 2.7.3 (default, Jan 13 2013, 11:20:46) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> x1=0xff
>>> x0=0xff
>>> if x1 > 15:
...   x1 = (((x1) & 0b1111))
...   x = ((x0) + (x1<<8))*-1
... else:
...   x= (x0) + (x1<<8)
... 
>>> x
-4095
>>> 
now, try this

Code: Select all

$ python
Python 2.7.3 (default, Jan 13 2013, 11:20:46) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> x1=0xff
>>> x0=0xff
>>> X=x0+(x1<<8)
>>> if X & 0x8000 :
...   X = (~X + 1) & 0xffff
...   X = -X
... 
>>> X
-1
>>> 
looks like i left out a step as i was dozing off last night.

sorry.

tldr
 
Posts: 466
Joined: Thu Aug 30, 2012 1:34 am

Re: ADXL345 with Python and the Raspberry Pi

Post by tldr »

you're error arises from a misunderstanding of the representation of negative numbers. although a negative number is easily identified as being negative by a simple examination of its high order bit, it is not just a positive number with its high order bit set to one. a two's complement number is formed by taking the bitwise complement of the number, (i.e. change all zeroes to ones and all ones to zero), and adding one to it. although this may seem a little bit baroque it has the advantage of simplifying the arithmetic logic in a computer.

a simple example....

first let's assume 8 bit arithmetic. the two's complement of b00000001 is formed by taking the bitwise complement of 1, b11111110, and adding one to it giving b1111111.

now, (keeping in mind that in binary addition 1 + 1 is 10, and you carry the 1), try adding 1 and negative one,

Code: Select all

  11111111
+ 00000001
__________
  00000000
the result is zer0 and the carry out of the high order bit sets the carry flag in the processors alu. this is like adding 1 to 99999999 in decimal arithmetic.

now try the same operation with the representation you coded for. again, assuming eight bit arithmetic, negative one would be represented as 1 with its high order bit set to indicate a negative number. addition of 1 and -1 would look like this...

Code: Select all

  10000001
+ 00000001
__________
  10000010
which, i guess would be -2.

clear as mud, right?

User avatar
static
 
Posts: 188
Joined: Thu Dec 23, 2010 6:21 pm

Re: ADXL345 with Python and the Raspberry Pi

Post by static »

Ugh. I've scuba'd through mud that was clearer than that!

Sorry about the long delay getting back here. Horrendous week. I may have to write a movie script...

OK, your name is "tldr", but I feel that if you're going to take the time to write the lesson down, I should read it and learn it. I'm looking at my code now versus your code... I'll admit, it gives me headaches, but your binary addition is what I needed to see.... I think.

I'm not sure how the statement:
if X & 0x8000:
evaluates. I'm trying to break it down in my head.

I keep trying out the expression:
X & 0x8000
from the python shell and it's evaluating as 0 (not true or false) so I don't understand the "if...then" statement using "if X & 0x8000".

Ahhh... I was doing it wrong. I was using 4-bit numbers instead of 8-bit numbers. Why are we mixing hexadecimal and binary together? Is there a reason for it? Can we just stick with two different numeric bases (decimal and binary)?

Before I forget (because I'm smiling right now) when you're replying, under options, select "Disable smiles". That'll fix 'em. No more smiles (take that, orphans!)

OK, I just fixed the problem, at least in my test code. I've got to swap machines real quick.

User avatar
static
 
Posts: 188
Joined: Thu Dec 23, 2010 6:21 pm

Re: ADXL345 with Python and the Raspberry Pi

Post by static »

Code: Select all

def BST2():
  x0 = int(input("First Value"))
  x1 = int(input("Second Value"))
  X = x0 + (x1<<8)

  if x1 > 15:
    print("True")
    x1 = (x1 & 0b1111)
    print("Subtotal x1 ",x1)
    X = (x0 + (x1<<8))+1
    X = -X
    print("Subtotal X ", X)
    #x = x * -1

  print(X)
  print(bin(X))

z = 0
while z == 0:
  BST2()
  z=0

OK, that will let you test out numbers very quickly. If the first input is 0 and the second input is 16, the result is -1. If both inputs are 255 then the result is -4096. The whole range is mapped, and I think it is mapped correctly.

I'm going to try to rebuild the sensor and test out the library. I was doing some fit testing today on the actual project, to see how I was going to mount it.

User avatar
static
 
Posts: 188
Joined: Thu Dec 23, 2010 6:21 pm

Re: ADXL345 with Python and the Raspberry Pi

Post by static »

Oh wow, it seems to work!

New code:

Code: Select all

#!/usr/bin/python
# coding=<UTF-8> 

import time
from Adafruit_I2C import Adafruit_I2C

# ===========================================================================
# ADXL345 Class, written for Python 3.x Modified 4-28-13 by Static
# This is definitely a work in progress.  This code relies on the
# Adafruit_I2C.py code.  Please support the open source movement, and those
# dedicated to open source.  www.adafruit.com
# If you find this code useful or have suggestions, hit me up at:
# medicforlife.blogspot.com
# As it stands, the code isn't commented out.  A ton of revision still needs to happen
# The end goal of this code is to spit out acceleration readings on demand.
# Due to the constraints of the ADXL345, this will always be three readings, X,Y,Z
# Thanks to tldr for making me do the math correctly.
# ===========================================================================

class ADXL345 :
  i2c = None

  # Registers
  __ADXL345_DEVID = 0x00
  __ADXL345_THRESH_TAP = 0x1D	  #8 bits
  __ADXL345_X_OFFSET = 0x1E	  #8 bits
  __ADXL345_Y_OFFSET = 0x1F	  #8 bits
  __ADXL345_Z_OFFSET = 0x20	  #8 bits
  __ADXL345_TAP_DUR = 0x21	  #8 bits
  __ADXL345_TAP_LATENCY = 0x22	  #8 bits
  __ADXL345_TAP_WINDOW = 0x23	  #8 bits
  __ADXL345_THRESH_ACT = 0x24	  #8 bits
  __ADXL345_THRESH_INACT = 0x25	  #8 bits
  __ADXL345_TIME_INACT = 0x26	  #8 bits
  __ADXL345_ACT_INACT_CTL = 0x27
  __ADXL345_THRESH_FF = 0x28	  #8 bits
  __ADXL345_TIME_FF = 0x29	  #8 bits
  __ADXL345_TAP_AXES = 0x2A	  
  __ADXL345_ACT_TAP_STATUS = 0x2B
  __ADXL345_BW_RATE = 0x2C
  __ADXL345_PWR_CTL = 0x2D
  __ADXL345_INT_ENABLE = 0x2E
  __ADXL345_INT_MAP = 0x2F
  __ADXL345_INT_SOURCE = 0x30
  __ADXL345_DATA_FORMAT = 0x31
  __ADXL345_DATA_X0 = 0x32	  #8 bits
  __ADXL345_DATA_X1 = 0x33	  #8 bits
  __ADXL345_DATA_Y0 = 0x34	  #8 bits
  __ADXL345_DATA_Y1 = 0x35	  #8 bits
  __ADXL345_DATA_Z0 = 0x36	  #8 bits
  __ADXL345_DATA_Z1 = 0x37	  #8 bits
  __ADXL345_FIFO_CTL = 0x38
  __ADXL345_FIFO_STATUS = 0x39

  # Datarate controls using BW_RATE register 0x2c
  __ADXL345_DR_3200 = 0b00001111
  __ADXL345_DR_1600 = 0b00001110
  __ADXL345_DR_800 = 0b00001101
  __ADXL345_DR_400 = 0b00001100
  __ADXL345_DR_200 = 0b00001011
  __ADXL345_DR_100 = 0b00001010
  __ADXL345_DR_50 = 0b00001001
  __ADXL345_DR_25 = 0b00001000
  __ADXL345_DR_12_5 = 0b00000111
  __ADXL345_DR_6_25 = 0b00000110

  # Datarate controls using BW_RATE at low power
  __ADXL345_DR_400 = 0b00011100
  __ADXL345_DR_200 = 0b00011011
  __ADXL345_DR_100 = 0b00011010
  __ADXL345_DR_50 = 0b00011001
  __ADXL345_DR_25 = 0b00011000
  __ADXL345_DR_12_5 = 0b00010111

  # Data Format using DATA_FORMAT 0x31
  __ADXL345_SELFTEST =    0b10000000
  __ADXL345_SPI_BIT =     0b01000000
  __ADXL345_INT_INVERT =  0b00100000
  __ADXL345_FULL_RES =    0b00001000
  __ADXL345_JUSTIFY =     0b00000100
  __ADXL345_2G =          0b00000000
  __ADXL345_4G =          0b00000001
  __ADXL345_8G =          0b00000010
  __ADXL345_16G =         0b00000011

  # FIFO Control using FIFO_CTL 0x38
  __ADXL345_BYPASS =      0b00000000
  __ADXL345_FIFO =        0b01000000
  __ADXL345_STREAM =      0b10000000
  __ADXL345_TRIG_MODE =   0b11000000
  __ADXL345_TRIG_INT1 =   0b00000000
  __ADXL345_TRIG_INT2 =   0b00100000
  __ADXL345_SAMPLES31 =   0b00011111
  __ADXL345_SAMPLES16 =   0b00010000
  __ADXL345_SAMPLES10 =   0b00001010

  # Power control using PWR_CTL 0x2D
  __ADXL345_LINK_BIT    = 0b00100000
  __ADXL345_AUTO_SLEEP  = 0b00010000
  __ADXL345_MEASURE     = 0b00001000
  __ADXL345_STANDBY     = 0b00000000
  __ADXL345_SLEEP       = 0b00000100
  __ADXL345_WAKEUP8HZ   = 0b00000000
  __ADXL345_WAKEUP4HZ   = 0b00000001
  __ADXL345_WAKEUP2HZ   = 0b00000010
  __ADXL345_WAKEUP1HZ   = 0b00000011
  

  


  # Constructor
  def __init__(self, address = 0x53, busnum = -1, debug = False):
    self.i2c = Adafruit_I2C(address, busnum, debug)
    self.address = address
    self.debug = debug
    if address == 0x53:
      self.__ADXL345_WRITE = 0xA6
      self.__ADXL345_READ = 0xA7
    elif address == 0x1D:
      self.__ADXL345_WRITE = 0x3A
      self.__ADXL345_READ = 0x3B
    else:
      if self.debug == True:
        print("Invalid I2C Address for ADXL345: ", self.address)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY) 
    self.i2c.write8(self.__ADXL345_BW_RATE, self.__ADXL345_DR_100)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, (self.__ADXL345_2G + self.__ADXL345_FULL_RES))
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)

  def gravTest(self):
    interval = 0.1
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, self.__ADXL345_2G)
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE)
    time.sleep(interval)
    print("2G self test values X,Y,Z",self.readAccel(0.0043))
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, self.__ADXL345_4G)
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE)
    time.sleep(interval)
    print("4G self test values X,Y,Z",self.readAccel((0.0043*2)))
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, self.__ADXL345_8G)
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE)
    time.sleep(interval)
    print("8G self test values X,Y,Z",self.readAccel((0.0043*4)))
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, self.__ADXL345_16G)
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE)
    time.sleep(interval)
    print("16G self test values X,Y,Z",self.readAccel((0.0043*8)))

  def quickCalibrate(self, cycles):
    i = 0
    x,y,z,xrun,yrun,zrun,xavg,yavg,zavg = 0,0,0,0,0,0,0,0,0
    for i in range(cycles):
      x,y,z = self.readAccel(0.0043)
      xrun = xrun+x
      yrun = yrun+y
      zrun = zrun+z
    xavg = xrun/cycles
    yavg = yrun/cycles
    zavg = zrun/cycles
    print(xavg,yavg,zavg)
    
    



  def readAccel(self):
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE) # Set power control to measure
    x0 = self.i2c.readU8(self.__ADXL345_DATA_X0)                    # Read X-Axis 0
    x1 = self.i2c.readU8(self.__ADXL345_DATA_X1)                    # Read X-Axis 1
    X = x0 + (x1 << 8)                                              # By default, add the two together (bit-shift x1)
    if (x1 > 15):                                                   # if x1 signifies a negative
      x1 = (x1 & 0b1111)                                            # don't count the first 4 bits
      X = (x0 + (x1 << 8))+1                                        # bit shift and add to x0, then add 1
      X = -X                                                        # then multiple by -1 (make this a negative value)
      
    y0 = self.i2c.readU8(self.__ADXL345_DATA_Y0)
    y1 = self.i2c.readU8(self.__ADXL345_DATA_Y1)
    Y = y0 + (y1 << 8)
    if (y1 > 15):
      y1 = (y1 & 0b1111)
      Y = (y0 + (y1 << 8))+1
      Y = -Y
    
    z0 = self.i2c.readU8(self.__ADXL345_DATA_Z0)
    z1 = self.i2c.readU8(self.__ADXL345_DATA_Z1)
    Z = z0 + (z1 << 8)
    if (z1 > 15):
      z1 = (z1 & 0b1111)
      Z = (z0 + (z1 << 8))+1
      Z = -Z
    
    if self.debug == True:
      print(X,Y,Z)
    return X,Y,Z

  def scaledAccel(self, ScaleFactor):
    x,y,z = self.readAccel()
    x = x * ScaleFactor
    y = y * ScaleFactor
    z = z * ScaleFactor
    return x,y,z
    


hobbes901
 
Posts: 6
Joined: Tue May 14, 2013 5:21 am

Re: ADXL345 with Python and the Raspberry Pi

Post by hobbes901 »

Just stumbled across this while looking for ways to hook up my ADXL345. I'm using it to help keep a servo operated mount level. The code you've put together works great for me! :D

One thing I did add in is a short bit of code for x,y and z readings to make them easier to handle. The problem I was having was that I needed to keep the value around 0 but as it moved back and forth it jumped from 10 to -4090. To make this simpler I added in the following code to change the scale so that those values became 10 to -10. errr if that makes any sense.

Code: Select all

if x<0:
    x=-(x+4095)
I did this for x,y and z meaning that they now all read from 255 to -255 around 0 which I think is easier to deal with.

User avatar
static
 
Posts: 188
Joined: Thu Dec 23, 2010 6:21 pm

Re: ADXL345 with Python and the Raspberry Pi

Post by static »

Typically I think you want to use a function to modify the output of a sensor, instead of directly modifying the sensor. That way you can still call the plain vanilla function if you need to.
It sounds like you're "balancing" a servo. You may want to look at a PID function. From what I've heard, PID is difficult to learn, but once it is learned the results are incredible (Segways, quadrocopters, etc)
http://en.wikipedia.org/wiki/PID_controller

Best of luck! Thanks for posting up. What are you working on?

hobbes901
 
Posts: 6
Joined: Tue May 14, 2013 5:21 am

Re: ADXL345 with Python and the Raspberry Pi

Post by hobbes901 »

Thanks for the tip I'll look into that PID stuff, I done something similar before in a different system that might be transferable.

I'm building a microscope system which relies on the microscope head always being level. As it should only need minor adjustments every time the head is moved I hopefully wont need anything too complicated but the PID route looks like a really stable solution.

User avatar
static
 
Posts: 188
Joined: Thu Dec 23, 2010 6:21 pm

Re: ADXL345 with Python and the Raspberry Pi

Post by static »

Oh wow!
Would you keep me updated? I'm looking at a project that could benefit from that level of precision, but I'm still stuck in some "weeds".

I'm really interested because I used to have a nice lab grade microscope for home research and photography. I had to sell it during a "tight time", and miss it.

hobbes901
 
Posts: 6
Joined: Tue May 14, 2013 5:21 am

Re: ADXL345 with Python and the Raspberry Pi

Post by hobbes901 »

Will do I post updates on my project here <shameless_plug> errantscience.com and I will making all the code write for it freely available because...well it's raspberry pi isn't that what everyone should do! :)

User avatar
static
 
Posts: 188
Joined: Thu Dec 23, 2010 6:21 pm

Re: ADXL345 with Python and the Raspberry Pi

Post by static »

You may have just made it to my daily reading list.
"Poking science with a stick"
Beautiful!

praajhen
 
Posts: 2
Joined: Wed Jun 19, 2013 11:43 am

Re: ADXL345 with Python and the Raspberry Pi

Post by praajhen »

Hello Static,

I am working on Python and would like to use your code but i've some doubts please reply as soon as possible.
How to visualize the o/p acceleration data graphically ?

Code: Select all

#!/usr/bin/python
# coding=<UTF-8> 

import time
from Adafruit_I2C import Adafruit_I2C

# ===========================================================================
# ADXL345 Class, written for Python 3.x Modified 4-20-13 by Static
# This is definitely a work in progress.  This code relies on the
# Adafruit_I2C.py code.  Please support the open source movement, and those
# dedicated to open source.  www.adafruit.com
# If you find this code useful or have suggestions, hit me up at:
# medicforlife.blogspot.com
# As it stands, the code isn't commented out.  A ton of revision needs to happen
# The end goal of this code is to spit out acceleration readings on demand.
# Due to the constraints of the ADXL345, this will always be three readings, X,Y,Z
# ===========================================================================

class ADXL345 :
  i2c = None

  # Registers
  __ADXL345_DEVID = 0x00
  __ADXL345_THRESH_TAP = 0x1D	  #8 bits
  __ADXL345_X_OFFSET = 0x1E	  #8 bits
  __ADXL345_Y_OFFSET = 0x1F	  #8 bits
  __ADXL345_Z_OFFSET = 0x20	  #8 bits
  __ADXL345_TAP_DUR = 0x21	  #8 bits
  __ADXL345_TAP_LATENCY = 0x22	  #8 bits
  __ADXL345_TAP_WINDOW = 0x23	  #8 bits
  __ADXL345_THRESH_ACT = 0x24	  #8 bits
  __ADXL345_THRESH_INACT = 0x25	  #8 bits
  __ADXL345_TIME_INACT = 0x26	  #8 bits
  __ADXL345_ACT_INACT_CTL = 0x27
  __ADXL345_THRESH_FF = 0x28	  #8 bits
  __ADXL345_TIME_FF = 0x29	  #8 bits
  __ADXL345_TAP_AXES = 0x2A	  
  __ADXL345_ACT_TAP_STATUS = 0x2B
  __ADXL345_BW_RATE = 0x2C
  __ADXL345_PWR_CTL = 0x2D
  __ADXL345_INT_ENABLE = 0x2E
  __ADXL345_INT_MAP = 0x2F
  __ADXL345_INT_SOURCE = 0x30
  __ADXL345_DATA_FORMAT = 0x31
  __ADXL345_DATA_X0 = 0x32	  #8 bits
  __ADXL345_DATA_X1 = 0x33	  #8 bits
  __ADXL345_DATA_Y0 = 0x34	  #8 bits
  __ADXL345_DATA_Y1 = 0x35	  #8 bits
  __ADXL345_DATA_Z0 = 0x36	  #8 bits
  __ADXL345_DATA_Z1 = 0x37	  #8 bits
  __ADXL345_FIFO_CTL = 0x38
  __ADXL345_FIFO_STATUS = 0x39

  # Datarate controls using BW_RATE register 0x2c
  __ADXL345_DR_3200 = 0b00001111
  __ADXL345_DR_1600 = 0b00001110
  __ADXL345_DR_800 = 0b00001101
  __ADXL345_DR_400 = 0b00001100
  __ADXL345_DR_200 = 0b00001011
  __ADXL345_DR_100 = 0b00001010
  __ADXL345_DR_50 = 0b00001001
  __ADXL345_DR_25 = 0b00001000
  __ADXL345_DR_12_5 = 0b00000111
  __ADXL345_DR_6_25 = 0b00000110

  # Datarate controls using BW_RATE at low power
  __ADXL345_DR_400 = 0b00011100
  __ADXL345_DR_200 = 0b00011011
  __ADXL345_DR_100 = 0b00011010
  __ADXL345_DR_50 = 0b00011001
  __ADXL345_DR_25 = 0b00011000
  __ADXL345_DR_12_5 = 0b00010111

  # Data Format using DATA_FORMAT 0x31
  __ADXL345_SELFTEST =    0b10000000
  __ADXL345_SPI_BIT =     0b01000000
  __ADXL345_INT_INVERT =  0b00100000
  __ADXL345_FULL_RES =    0b00001000
  __ADXL345_JUSTIFY =     0b00000100
  __ADXL345_2G =          0b00000000
  __ADXL345_4G =          0b00000001
  __ADXL345_8G =          0b00000010
  __ADXL345_16G =         0b00000011

  # FIFO Control using FIFO_CTL 0x38
  __ADXL345_BYPASS =      0b00000000
  __ADXL345_FIFO =        0b01000000
  __ADXL345_STREAM =      0b10000000
  __ADXL345_TRIG_MODE =   0b11000000
  __ADXL345_TRIG_INT1 =   0b00000000
  __ADXL345_TRIG_INT2 =   0b00100000
  __ADXL345_SAMPLES31 =   0b00011111
  __ADXL345_SAMPLES16 =   0b00010000
  __ADXL345_SAMPLES10 =   0b00001010

  # Power control using PWR_CTL 0x2D
  __ADXL345_LINK_BIT    = 0b00100000
  __ADXL345_AUTO_SLEEP  = 0b00010000
  __ADXL345_MEASURE     = 0b00001000
  __ADXL345_STANDBY     = 0b00000000
  __ADXL345_SLEEP       = 0b00000100
  __ADXL345_WAKEUP8HZ   = 0b00000000
  __ADXL345_WAKEUP4HZ   = 0b00000001
  __ADXL345_WAKEUP2HZ   = 0b00000010
  __ADXL345_WAKEUP1HZ   = 0b00000011
  

  


  # Constructor
  def __init__(self, address = 0x53, busnum = -1, debug = False):
    self.i2c = Adafruit_I2C(address, busnum, debug)
    self.address = address
    self.debug = debug
    if address == 0x53:
      self.__ADXL345_WRITE = 0xA6
      self.__ADXL345_READ = 0xA7
    elif address == 0x1D:
      self.__ADXL345_WRITE = 0x3A
      self.__ADXL345_READ = 0x3B
    else:
      if self.debug == True:
        print("Invalid I2C Address for ADXL345: ", self.address)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY) 
    self.i2c.write8(self.__ADXL345_BW_RATE, self.__ADXL345_DR_100)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, (self.__ADXL345_2G + self.__ADXL345_FULL_RES))
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)

  def gravTest(self):
    interval = 0.1
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, self.__ADXL345_2G)
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE)
    time.sleep(interval)
    print("2G self test values X,Y,Z",self.readAccel(0.0043))
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, self.__ADXL345_4G)
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE)
    time.sleep(interval)
    print("4G self test values X,Y,Z",self.readAccel((0.0043*2)))
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, self.__ADXL345_8G)
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE)
    time.sleep(interval)
    print("8G self test values X,Y,Z",self.readAccel((0.0043*4)))
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, self.__ADXL345_16G)
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE)
    time.sleep(interval)
    print("16G self test values X,Y,Z",self.readAccel((0.0043*8)))

  def quickCalibrate(self, cycles):
    i = 0
    x,y,z,xrun,yrun,zrun,xavg,yavg,zavg = 0,0,0,0,0,0,0,0,0
    for i in range(cycles):
      x,y,z = self.readAccel(0.0043)
      xrun = xrun+x
      yrun = yrun+y
      zrun = zrun+z
    xavg = xrun/cycles
    yavg = yrun/cycles
    zavg = zrun/cycles
    print(xavg,yavg,zavg)
    
    



  def readAccel(self, ScaleFactor):
    #ScaleFactor = 0.0043
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE)
    #time.sleep(0.0005)
    X = (self.i2c.readS16(self.__ADXL345_DATA_X0)) * ScaleFactor
    Y = (self.i2c.readS16(self.__ADXL345_DATA_Y0)) * ScaleFactor
    Z = (self.i2c.readS16(self.__ADXL345_DATA_Z0)) * ScaleFactor
    #X = (self.i2c.reverseByteOrder(self.i2c.readS16(self.__ADXL345_DATA_X0))) * ScaleFactor
    #Y = (self.i2c.reverseByteOrder(self.i2c.readS16(self.__ADXL345_DATA_Y0))) * ScaleFactor
    #Z = (self.i2c.reverseByteOrder(self.i2c.readS16(self.__ADXL345_DATA_Z0))) * ScaleFactor
    if self.debug == True:
      print("X0 = ", X0)
    return X,Y,Z
  
    

Current version of code:

Code: Select all

#!/usr/bin/python
# coding=<UTF-8> 

import time
from Adafruit_I2C import Adafruit_I2C

# ===========================================================================
# ADXL345 Class, written for Python 3.x Modified 5-3-13 by Static
# This is definitely a work in progress.  This code relies on the
# Adafruit_I2C.py code.  Please support the open source movement, and those
# dedicated to open source.  www.adafruit.com
# If you find this code useful or have suggestions, hit me up at:
# medicforlife.blogspot.com
# As it stands, the code isn't commented out.  A ton of revision still needs to happen
# The end goal of this code is to spit out acceleration readings on demand.
# Due to the constraints of the ADXL345, this will always be three readings, X,Y,Z
# Thanks to tldr for making me do the math correctly.
# ===========================================================================

class ADXL345 :
  i2c = None

  # Registers
  __ADXL345_DEVID = 0x00
  __ADXL345_THRESH_TAP = 0x1D	  #8 bits
  __ADXL345_X_OFFSET = 0x1E	  #8 bits
  __ADXL345_Y_OFFSET = 0x1F	  #8 bits
  __ADXL345_Z_OFFSET = 0x20	  #8 bits
  __ADXL345_TAP_DUR = 0x21	  #8 bits
  __ADXL345_TAP_LATENCY = 0x22	  #8 bits
  __ADXL345_TAP_WINDOW = 0x23	  #8 bits
  __ADXL345_THRESH_ACT = 0x24	  #8 bits
  __ADXL345_THRESH_INACT = 0x25	  #8 bits
  __ADXL345_TIME_INACT = 0x26	  #8 bits
  __ADXL345_ACT_INACT_CTL = 0x27
  __ADXL345_THRESH_FF = 0x28	  #8 bits
  __ADXL345_TIME_FF = 0x29	  #8 bits
  __ADXL345_TAP_AXES = 0x2A	  
  __ADXL345_ACT_TAP_STATUS = 0x2B
  __ADXL345_BW_RATE = 0x2C
  __ADXL345_PWR_CTL = 0x2D
  __ADXL345_INT_ENABLE = 0x2E
  __ADXL345_INT_MAP = 0x2F
  __ADXL345_INT_SOURCE = 0x30
  __ADXL345_DATA_FORMAT = 0x31
  __ADXL345_DATA_X0 = 0x32	  #8 bits
  __ADXL345_DATA_X1 = 0x33	  #8 bits
  __ADXL345_DATA_Y0 = 0x34	  #8 bits
  __ADXL345_DATA_Y1 = 0x35	  #8 bits
  __ADXL345_DATA_Z0 = 0x36	  #8 bits
  __ADXL345_DATA_Z1 = 0x37	  #8 bits
  __ADXL345_FIFO_CTL = 0x38
  __ADXL345_FIFO_STATUS = 0x39

  # Datarate controls using BW_RATE register 0x2c
  __ADXL345_DR_3200 = 0b00001111
  __ADXL345_DR_1600 = 0b00001110
  __ADXL345_DR_800 = 0b00001101
  __ADXL345_DR_400 = 0b00001100
  __ADXL345_DR_200 = 0b00001011
  __ADXL345_DR_100 = 0b00001010
  __ADXL345_DR_50 = 0b00001001
  __ADXL345_DR_25 = 0b00001000
  __ADXL345_DR_12_5 = 0b00000111
  __ADXL345_DR_6_25 = 0b00000110

  # Datarate controls using BW_RATE at low power
  __ADXL345_DR_400 = 0b00011100
  __ADXL345_DR_200 = 0b00011011
  __ADXL345_DR_100 = 0b00011010
  __ADXL345_DR_50 = 0b00011001
  __ADXL345_DR_25 = 0b00011000
  __ADXL345_DR_12_5 = 0b00010111

  # Data Format using DATA_FORMAT 0x31
  __ADXL345_SELFTEST =    0b10000000
  __ADXL345_SPI_BIT =     0b01000000
  __ADXL345_INT_INVERT =  0b00100000
  __ADXL345_FULL_RES =    0b00001000
  __ADXL345_JUSTIFY =     0b00000100
  __ADXL345_2G =          0b00000000
  __ADXL345_4G =          0b00000001
  __ADXL345_8G =          0b00000010
  __ADXL345_16G =         0b00000011

  # FIFO Control using FIFO_CTL 0x38
  __ADXL345_BYPASS =      0b00000000
  __ADXL345_FIFO =        0b01000000
  __ADXL345_STREAM =      0b10000000
  __ADXL345_TRIG_MODE =   0b11000000
  __ADXL345_TRIG_INT1 =   0b00000000
  __ADXL345_TRIG_INT2 =   0b00100000
  __ADXL345_SAMPLES31 =   0b00011111
  __ADXL345_SAMPLES16 =   0b00010000
  __ADXL345_SAMPLES10 =   0b00001010

  # Power control using PWR_CTL 0x2D
  __ADXL345_LINK_BIT    = 0b00100000
  __ADXL345_AUTO_SLEEP  = 0b00010000
  __ADXL345_MEASURE     = 0b00001000
  __ADXL345_STANDBY     = 0b00000000
  __ADXL345_SLEEP       = 0b00000100
  __ADXL345_WAKEUP8HZ   = 0b00000000
  __ADXL345_WAKEUP4HZ   = 0b00000001
  __ADXL345_WAKEUP2HZ   = 0b00000010
  __ADXL345_WAKEUP1HZ   = 0b00000011
  

  


  # Constructor
  def __init__(self, address = 0x53, busnum = -1, debug = False):
    self.i2c = Adafruit_I2C(address, busnum, debug)
    self.address = address
    self.debug = debug
    self.xcal = False
    self.ycal = False
    self.zcal = False
    if address == 0x53:
      self.__ADXL345_WRITE = 0xA6
      self.__ADXL345_READ = 0xA7
    elif address == 0x1D:
      self.__ADXL345_WRITE = 0x3A
      self.__ADXL345_READ = 0x3B
    else:
      if self.debug == True:
        print("Invalid I2C Address for ADXL345: ", self.address)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY) 
    self.i2c.write8(self.__ADXL345_BW_RATE, self.__ADXL345_DR_100)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, (self.__ADXL345_2G + self.__ADXL345_FULL_RES))
    self.gScale = 2
    self.scale = 0.043
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)

  def setgScale2(self):
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, (self.__ADXL345_2G + self.__ADXL345_FULL_RES))
    self.gscale = 2
    self.scale = 0.043

  def setgScale4(self):
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, (self.__ADXL345_4G + self.__ADXL345_FULL_RES))
    self.gscale = 4
    self.scale = 2 * 0.043

  def setgScale8(self):
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, (self.__ADXL345_8G + self.__ADXL345_FULL_RES))
    self.gscale = 8
    self.scale = 4 * 0.043

  def setgScale16(self):
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, (self.__ADXL345_16G + self.__ADXL345_FULL_RES))
    self.gscale = 16
    self.scale = 8 * 0.043

  def getgScale(self):
    return self.gscale
  def getScale(self):
    return self.scale

  def gravTest(self):
    interval = 0.1
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, self.__ADXL345_2G)
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE)
    time.sleep(interval)
    print("2G self test values X,Y,Z",self.scaledAccel(0.0043))
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, self.__ADXL345_4G)
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE)
    time.sleep(interval)
    print("4G self test values X,Y,Z",self.scaledAccel((0.0043*2)))
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, self.__ADXL345_8G)
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE)
    time.sleep(interval)
    print("8G self test values X,Y,Z",self.scaledAccel((0.0043*4)))
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_STANDBY)
    self.i2c.write8(self.__ADXL345_DATA_FORMAT, self.__ADXL345_16G)
    self.i2c.write8(self.__ADXL345_FIFO_CTL, self.__ADXL345_STREAM)
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE)
    time.sleep(interval)
    print("16G self test values X,Y,Z",self.scaledAccel((0.0043*8)))

  def quickCalibrate(self, cycles = 100):
    i = 0
    x,y,z,xrun,yrun,zrun,xavg,yavg,zavg = 0,0,0,0,0,0,0,0,0
    for i in range(cycles):
      x,y,z = self.readAccel()
      xrun = xrun+x
      yrun = yrun+y
      zrun = zrun+z
    xavg = xrun/cycles
    yavg = yrun/cycles
    zavg = zrun/cycles
    if self.debug == True:
      print(xavg,yavg,zavg)
    self.xcal = xavg
    self.ycal = yavg
    self.zcal = zavg
    #return self.xcal, self.ycal, self.zcal



  def readAccelCal(self):
    if self.xcal == False or self.ycal == False or self.zcal == False:
      self.quickCalibrate()
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE) # Set power control to measure
    x0 = self.i2c.readU8(self.__ADXL345_DATA_X0)                    # Read X-Axis 0
    x1 = self.i2c.readU8(self.__ADXL345_DATA_X1)                    # Read X-Axis 1
    X = x0 + (x1 << 8)                                              # By default, add the two together (bit-shift x1)
    if (x1 > 15):                                                   # if x1 signifies a negative
      x1 = (x1 & 0b1111)                                            # don't count the first 4 bits
      X = (x0 + (x1 << 8))+1                                        # bit shift and add to x0, then add 1
      X = -X                                                        # then multiply by -1 (make this a negative value)
      
    y0 = self.i2c.readU8(self.__ADXL345_DATA_Y0)
    y1 = self.i2c.readU8(self.__ADXL345_DATA_Y1)
    Y = y0 + (y1 << 8)
    if (y1 > 15):
      y1 = (y1 & 0b1111)
      Y = (y0 + (y1 << 8))+1
      Y = -Y
    
    z0 = self.i2c.readU8(self.__ADXL345_DATA_Z0)
    z1 = self.i2c.readU8(self.__ADXL345_DATA_Z1)
    Z = z0 + (z1 << 8)
    if (z1 > 15):
      z1 = (z1 & 0b1111)
      Z = (z0 + (z1 << 8))+1
      Z = -Z
    
    if self.debug == True:
      print(X - self.xcal, Y - self.ycal, Z - self.zcal)
    return X - self.xcal, Y - self.ycal, Z - self.zcal              # subtract the quick calibrate average values and return

  def scaledAccel(self, ScaleFactor):
    x,y,z = self.readAccel()
    x = x * ScaleFactor
    y = y * ScaleFactor
    z = z * ScaleFactor
    return x,y,z

  def scaledAccelCal(self, ScaleFactor):
    x,y,z = self.readAccelCal()
    x = x * ScaleFactor
    y = y * ScaleFactor
    z = z * ScaleFactor
    return x,y,z
    

    



  def readAccel(self):
    self.i2c.write8(self.__ADXL345_PWR_CTL, self.__ADXL345_MEASURE) # Set power control to measure
    x0 = self.i2c.readU8(self.__ADXL345_DATA_X0)                    # Read X-Axis 0
    x1 = self.i2c.readU8(self.__ADXL345_DATA_X1)                    # Read X-Axis 1
    X = x0 + (x1 << 8)                                              # By default, add the two together (bit-shift x1)
    if (x1 > 15):                                                   # if x1 signifies a negative
      x1 = (x1 & 0b1111)                                            # don't count the first 4 bits
      X = (x0 + (x1 << 8))+1                                        # bit shift and add to x0, then add 1
      X = -X                                                        # then multiply by -1 (make this a negative value)
      
    y0 = self.i2c.readU8(self.__ADXL345_DATA_Y0)
    y1 = self.i2c.readU8(self.__ADXL345_DATA_Y1)
    Y = y0 + (y1 << 8)
    if (y1 > 15):
      y1 = (y1 & 0b1111)
      Y = (y0 + (y1 << 8))+1
      Y = -Y
    
    z0 = self.i2c.readU8(self.__ADXL345_DATA_Z0)
    z1 = self.i2c.readU8(self.__ADXL345_DATA_Z1)
    Z = z0 + (z1 << 8)
    if (z1 > 15):
      z1 = (z1 & 0b1111)
      Z = (z0 + (z1 << 8))+1
      Z = -Z
    
    if self.debug == True:
      print(X,Y,Z)
    return X,Y,Z

  def scaledAccel(self, ScaleFactor):
    x,y,z = self.readAccel()
    x = x * ScaleFactor
    y = y * ScaleFactor
    z = z * ScaleFactor
    return x,y,z
    

[/quote]

Locked
Please be positive and constructive with your questions and comments.

Return to “General Project help”