Sunday, 29 June 2014

Raspberry Pi - ADXL345 Accelerometer & Python


A little while ago I got my hands on a Adafuit ADXL345 (a triple axis accelerometer) from pimoroni, you can also get them from Amazon (US, UK) if that's easier, and I finally got around to setting it up.

Pimoroni also provide a really useful python module to interacting with the ADXL345 which you can get from github - https://github.com/pimoroni/adxl345-python.

Connecting it up
Wiring up the accelerometer is pretty easy, there are only 4 connections:

Raspberry Pi -> ADXL345:
  • GND - GND 
  • 3V - 3V3
  • SDA - SDA
  • SCL - SCL

Configure your Pi
The ADXL345 supports both I2C and SPI connections, I used I2C, which requires some configuration on the Pi:

Add the I2C modules to the Pi's configuration:
sudo nano /etc/modules
add the following lines:
i2c-bcm2708
i2c-dev
Remove I2C from the blacklist:
sudo nano /etc/modprobe.d/raspi-blacklist.conf
comment out:
blacklist i2c-bcm2708
so its:
#blacklist i2c-bcm2708
Reboot to make the changes:
sudo shutdown -r now
Install Software
You will need to install some software:
sudo apt-get install python-smbus i2c-tools git-core
Test ADXL345
You can check that your ADXL345 is found on the I2C bus, by running:
sudo i2cdetect -y 1
You should see a device at address 53


Download the ADXL345 pimoroni python library from github:
git clone https://github.com/pimoroni/adxl345-python
Run the example code and test it is working:
cd adxl345-python
sudo python example.py
You should see the G readings from the ADXL345.


If you get 0.000G for all axis then something probably isn't set-up correctly.

Writing your own python program
The adxl345-python project from pimoroni contains a python module for reading data from the ADXL345 perhaps not unsurprisingly called "adxl345.py", inside there is a class called "ADXL345" which is how you to interact with the accelerometer

The program below imports the module, instantiates an ADXL345 object and reads values from the accelerometer as g-forces.
#import the adxl345 module
import adxl345

#create ADXL345 object
accel = adxl345.ADXL345()

#get axes as g
axes = accel.getAxes(True)
# to get axes as ms^2 use
#axes = accel.getAxes(False)

#put the axes into variables
x = axes['x']
y = axes['y']
z = axes['z']

#print axes
print x
print y
print z
Change sensitivity
You can change the sensitivity of the ADXL345 by using the .setRange() method of the class.

The default range is 2g which means that the maximum G the ADXL345 can measure is 2.048, but at a high degree of sensitivity, you can change it so the maximum is 2g, 4g, 8g or 16g but with a lower level of sensitivity using:
accel.setRange(adxl345.RANGE_2G)
accel.setRange(adxl345.RANGE_4G)
accel.setRange(adxl345.RANGE_8G)
accel.setRange(adxl345.RANGE_16G)
Its a great accelerometer and really easy to use in your python projects.

55 comments:

  1. Hi,

    It doesn't work with my RPi Model B Rev 2. I tried all that you said in your post. I don't know why I can't read any address. I connected all wires in the correct gpio pin, so I don't understand (I have two Rpi, same model...same results)

    Can you help me?

    ReplyDelete
    Replies
    1. Hi,

      Does the module show up when you run sudo i2cdetect -y 1 ? Or are any errors shown?

      If there are no errors and it doesn't show up I suspect its either not wired up properly or doesn't work.

      Mart

      p.s. I wrote this setup based on a model b rev 2.

      Delete
    2. Connect the CS pin to HIGH (Vs / 3.3V). This fixed it for me.

      Delete
    3. Thank you, Diego. Setting CS to high did it for me, too.

      Delete
  2. Hi,

    there is any error when I run sudo i2cdetect -y 1 .. I'll try with other sensor.

    Regards,

    ReplyDelete
  3. When you say "SDL", I assume you mean "SCL"?

    ReplyDelete
    Replies
    1. I do indeed, a slip of the keyboard. Post updated!

      Delete
  4. Could i connect multiple Accelerometers?

    ReplyDelete
    Replies
    1. yes sure its how you connect SD0 you can change the i2c bus adress
      with a other adress you can read a other device

      http://wiki.analog.com/resources/tools-software/linux-drivers/input-misc/adxl345

      Configuration

      Selectable ADXL34X I2C Device Address:
      SDO I2C Address
      0 0x53
      1 0x1D

      Delete
  5. I would like to use the accelerometer data to set off a buzzer if a car is tilted 15 degrees to horizontal. Any ideas how to do this in Python. I'm very new to this , but I'm trying hard to introduce the raspberry Pi into our high school curriculum. Any help much appreciated!!

    ReplyDelete
    Replies
    1. That doesnt sound too complicated. You will need to work out the maths to convert g to 3d angles (http://lmgtfy.com/?q=accelerometer+calculate+angle). Then an if statement and turn on a GPIO pin which is connected to a buzzer.

      Delete
  6. Why does it show ~1g on the Z axis while sitting stationary?

    In order to get an accurate reading while vibrating, should the ~1g be subtracted?

    Great write up, it's super appreciated!

    ReplyDelete
    Replies
    1. Right if I understand you correctly... It measures 1g on the Z axis (which is presumably down for you), because the earth is pulling it down to the tune of 1g!

      Delete
  7. Hi,
    Thank you for your tutorial, it is really helpful. It works perfectly on Python 2 (Idle) but I have problems on Python 3 (Idle3). Error message: "ImportError: No module named smbus". Any idea what to do?

    ReplyDelete
    Replies
    1. python-smbus is installed (newest version).

      Delete
  8. Hi
    I got the wrong values. While not woving the acceleration is much greater then the acceleration of the earth. I ve got two sensors and both of them messure nearly the same wrong values. Cann you say me what to do?
    Thanks for your help

    ReplyDelete
    Replies
    1. For instance:
      root@raspberry: /DatenManuel/ADXL345/adxl345-python# python example.py
      ADXL345 on address 0x53:
      x=-0.640G
      y=-1.092G
      z=2.044G

      Do you have any idea how to fix that?

      Delete
    2. And that is when the accelerometer is flat on a surface not being moved? If so, no idea. Although if you minus out all the values you do get to about 1g. I wonder if it just needs calibrating, I never had to do mine but adafruit have a tutorial https://learn.adafruit.com/adxl345-digital-accelerometer/programming

      Delete
    3. Those are not invalid numbers. Could you describe us how is the accelerometer displayed over your test surface? May be necessary to calibrate the sensor in order to correct the baseline (removing the offset)

      Where did you buy your sensors?

      Regards

      Delete
  9. News: z axis seems to be stuck on z=2.044G even if I move the sensor. x and y are changing the values.

    ReplyDelete
  10. root@raspberrypi:/DatenManuel/ADXL345/adxl345-python# sudo python myexample.py
    ADXL345 on address 0x53:
    x = -0.652G
    y = -1.100G
    z = 2.044G
    x = -0.652G
    y = -1.100G
    z = 2.044G
    x = -0.640G
    y = -1.108G
    z = 2.044G
    x = -0.652G
    y = -1.104G
    z = 2.044G
    x = -0.644G
    y = -1.100G
    z = 2.044G
    x = -0.644G
    y = -1.104G
    z = 2.044G
    x = -0.648G
    y = -1.108G
    z = 2.044G
    x = -0.620G
    y = -1.456G
    z = 2.044G
    x = -0.680G
    y = -0.676G
    z = 2.044G
    x = -1.908G
    y = -1.508G
    z = 2.044G

    ReplyDelete
    Replies
    1. Is it the ADXL345 accelerometer

      Delete
    2. well of corse... i just wrote myexample.py with a Loop to take several messurements instead of one ... i don't now what to do now....

      Delete
    3. Perhaps try calibrating the accelerometer. Other than that, I would be tempted to start again. Reimage, reconnect, recode.

      Delete
    4. How to calibrate? I don't understand how to manage to adapt the arduino tutorial to raspberry

      Delete
  11. Hi, i follow the step exactly as you said.
    I'm using Raspberry Pi 2, and the address I've got is !E instead...

    When i run the python code, I get only one reading no matter how i move my accelerometer (ADXL345)

    ADXL345 on address 0x1e:
    x = 20.480G
    y = 120.840G
    z = 0.276G

    mind helping??

    ReplyDelete
    Replies
    1. Those values are definitely not right. are you sure these arent the readings from a different device? Im pretty sure this isnt from the accelerometer.

      Delete
  12. I record the time that I sample data. It appears that regardless of the value of BW_rate I enter, my rate hovers around 800 Hz. I have added a print statement, and the value that I expect gets passed into .setBandwidthRate. Any ideas as to what might be amiss? (I am actually using the SainSmart GY-85 board, a combo Accelerometer/compass/gyro, but it does use the ADXL345, and the address appears good and I am certainly getting good data from it.

    ReplyDelete
    Replies
    1. Sorry I dont have anything to add..

      Delete
    2. This comment has been removed by the author.

      Delete
    3. Did your error get solved ?? @Allen Takahashi

      Delete
  13. Hi it keeps showing importError: no module name adxl345 when I run it outside of the directory adxl345-Python. How do I get around this problem?

    ReplyDelete
    Replies
    1. Either copy the adxl345.py into your programs folder or package up adxl345 as a python module and install it.

      Delete
  14. Hi guys all is working well but would there be any way to make the ADXL345 take a consistent reading instead of having to hit enter every time?

    ReplyDelete
    Replies
    1. You should code some kind of trigger into a loop

      regards

      Delete
    2. For the example you might use this too...
      while true; do clear; sudo python example.py; sleep .1; done;

      Delete
  15. I followed the instructions but when I input sudo i2cdetect -y 1 I get an error that says No such file or directory exist.

    ReplyDelete
    Replies
    1. Its not an error ive seen before, it suggest i2cdetect isnt installed, are you using raspbian?

      Delete
    2. Your i2c is like still off. Use sudo raspi-config. select advanced options. and turn it on.

      Delete
  16. Hi! when i run the command : sudo python example.py, i get this error
    Traceback (most recent call last):
    File "example.py", line 11, in
    adxl345 = ADXL345()
    File "/home/pi/adxl345-python/adxl345.py", line 47, in __init__
    self.setBandwidthRate(BW_RATE_100HZ)
    File "/home/pi/adxl345-python/adxl345.py", line 55, in setBandwidthRate
    bus.write_byte_data(self.address, BW_RATE, rate_flag)
    IOError: [Errno 5] Input/output error

    ReplyDelete
    Replies
    1. I change the command to sudo python3.2 example.py to run it to python 3 and i get this error:
      File "example.py", line 14
      print "ADXL345 on address 0x%x:" % (adxl345.address)
      ^
      SyntaxError: invalid syntax

      Delete
    2. The code isn't python 3 compatible, hence why you get a syntax error.

      The input/output error suggests the Pi cant talk to the module.

      This post is a little old, I dont know if the methods of enabling I2C have changed. I vaguely remember there is an option in raspi-config to enable I2C nowadays.

      Delete
    3. This comment has been removed by the author.

      Delete
    4. i am using different adxl345 not from adafruit and when i use sudo i2cdetect -y 1 i get this result:
      0 1 2 3 4 5 6 7 8 9 a b c d e f
      00: -- -- -- -- -- -- -- -- -- -- -- -- --
      10: -- -- -- -- -- -- -- -- -- -- -- -- -- 1d -- --
      20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
      30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
      40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
      50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
      60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
      70: -- -- -- -- -- -- -- --

      i believe this adxl345 is using the address 1D. Please correct me if i am wrong

      Delete
    5. Well something is using 1d for sure..

      I had a quick look at pimoroni's library and you can pass in an address when you invoke the ADXL345 class, other than the default 53.

      So:

      accel = adxl345.ADXL345(0x1d)

      Whether the library will work with your accelerometer is a different question!

      Delete
    6. ok thank you! i will try it

      Delete
    7. Big thanks! I did what you said and i think it now working. You are right that it is not compatible to python 3 because i still get errors when i run it with it.

      Delete
    8. HI! can I ask if you could explain to me the following lines of code in your program?
      bytes = bus.read_i2c_block_data(self.address, AXES_DATA, 6)

      x = bytes[0] | (bytes[1] << 8)
      if(x & (1 << 16 - 1)):
      x = x - (1<<16)

      y = bytes[2] | (bytes[3] << 8)
      if(y & (1 << 16 - 1)):
      y = y - (1<<16)

      z = bytes[4] | (bytes[5] << 8)
      if(z & (1 << 16 - 1)):
      z = z - (1<<16)

      Thanks in advance

      Delete
    9. It is just pulling the x,y,z values from the raw data stream that gets returned from the accelerometer.

      Delete
    10. @Mark Aala, how did you sort out the issue of python

      print "ADXL345 on address 0x%x:" % (adxl345.address)
      ^
      SyntaxError: invalid syntax

      Following was my output

      pi@raspberrypi ~/adxl345-python $ sudo i2cdetect -y 1
      0 1 2 3 4 5 6 7 8 9 a b c d e f
      00: -- 04 05 06 -- 08 09 0a -- 0c 0d 0e --
      10: 10 11 12 -- 14 15 16 -- 18 19 1a -- 1c 1d 1e --
      20: 20 21 22 -- 24 25 26 -- 28 29 2a -- 2c 2d 2e --
      30: 30 -- 32 -- 34 -- 36 -- 38 39 3a -- 3c 3d 3e --
      40: 40 41 42 -- 44 45 46 -- 48 49 4a -- 4c 4d 4e --
      50: 50 -- 52 -- 54 -- 56 -- 58 -- 5a -- 5c -- 5e --
      60: 60 61 62 -- 64 65 66 -- 68 69 6a -- 6c 6d 6e --
      70: 70 71 72 -- 74 75 76 --

      Delete
  17. I was wondering how to get M/S using this accelerometer. Any help would be appreciated!

    ReplyDelete
  18. Hi, Will...what does M/S means for you? Are you thinking in velocity units? This kind of accelerometer isn't good enough for that kind of integration, unless you will measure high amplitude (in acceleration)

    Please, specify your question

    ReplyDelete
  19. Mine says "ImportError: No module named adxl345", please help :/

    ReplyDelete