Getting Started with Accelerometers and Micro-controllers: Arduino + ADXL335

My first home electronics project — a device to measure leg acceleration and balance while skiing — involved connecting an ADXL335 on a Sparkfun breakout board to an Arduino Uno.  Going in, I was an experienced programmer but knew nothing about electronics.  The online resources are good, but I found some important information was missing.  Some of it seems like stuff that just goes without saying in the community, but I’m going to go ahead and say it to save other newbies like myself any trouble.

So this is the post I wish I had found before I started working with the ADXL335.  I will assume that:

  • you know how to build simple circuits
  • you know how to write and upload a sketch
  • you know how to open the serial monitor

If you can’t do any of these things, go spend an hour playing with some of the basic examples at arduino.cc then come back here.

To get an ADXL335 talking to an Arduino, there is not much to do.  Here are the key steps:

  1. Solder pins to the breakout board or do something else to get a good connection.
  2. Build the circuit with 3.3V power and AREF to normalize the analog input.
  3. Write a basic sketch.
  4. Calibrate.

Let me elaborate.

1. Solder header pins to the breakout board (or do something else to get a good connection)

I had no idea I needed to do this, and I never read anything that told me I needed to do this.  This is one of those things that goes without saying.

When I got my breakout board in the mail, I thought all I needed to do was make sure I got wires touching those little holes in the board when I built my circuit, so I got a 6-pin header and plugged it in to the breakout board.

I got lousy data that bounced around and didn’t change noticeably when I moved the thing around and tilted it.  I thought I built the circuit wrong, but it was so simple.   Or maybe I had damaged the component?

Then I tried connecting wires in to the breakout board directly.  No luck.

Finally I noticed that all of the pictures of this thing I’d seen online had the headers soldered in.  Could that be it?

I bought a soldering iron and tried it.

6-pin header soldered crookedly on an ADXL335 breakout board. I need a better camera for this stuff.

It was my first soldering job, so it wasn’t pretty, but the data was beautiful.  It looked just like the examples I had seen online.

So do this before you bother building your circuit.

[There are other ways to get good connections -- pogo pins for example -- but do something to make sure you have a solid physical connection.]

2. Build the circuit with 3.3V power and AREF

This is something I was surprised about.  Many of the online examples I found for the ADXL335 and Arduino hooked the accelerometer up to 5V power even though the data sheet explicitly says not to exceed 3.6V.

It is easy enough to wire VCC to the 3.3V pin on the Arduino, but then you lose some of the resolution on your analog input because the analog-to-digital converter expects input up to 5V.

So you need to run a wire from 3.3V over to the AREF pin to.  Here is what my basic circuit looks like:

A basic circuit for interaction with an ADXL335 on a breakout board.

This image was produced with Fritzing.  Here is what my circuit looks like in real life:

A real life version of the circuit. It's much easier to understand a fritzing image.

This also requires changes to the code in your sketch.  So let’s talk about that now.

3. Write a sketch

The example sketch that shipped with my installation of the Arduino is based on a clever circuit that skips the breadboard and plugs the ADXL335 directly into the pins A0-A5 on the Arduino.  I like that setup except for one thing: It runs 5V power to my ADXL.  So I’ll write my own code to work with the circuit shown above.

First, define a few constants to make what follows easier to read, expand,  and maintain.  All we need to do here is define our input pins and a parameter that we use to set the time between samples.

// these constants describe the pins. They won't change:
const int xpin = A1;                  // x-axis of the accelerometer
const int ypin = A2;                  // y-axis
const int zpin = A3;                  // z-axis (only on 3-axis models)

int sampleDelay = 500;   //number of milliseconds between readings

Now write the setup routine.  Here we need to:

  1. Initialize serial communication
  2. Tell the analog-to-digital converter to use an external reference voltage (which comes in on the AREF pin).
  3. Set up our input pins.
It looks like this:
void setup()
{
  // initialize the serial communications:
  Serial.begin(9600);

  //Make sure the analog-to-digital converter takes its reference voltage from
  // the AREF pin
  analogReference(EXTERNAL);

  pinMode(xpin, INPUT);
  pinMode(ypin, INPUT);
  pinMode(zpin, INPUT);
}

Finally, in our loop routine we simply read the pins, write the values to serial, then wait a little bit.

void loop()
{

  Serial.print( analogRead(xpin));
  Serial.print("\t");

  //add a small delay between pin readings.  I read that you should
  //do this but haven't tested the importance
    delay(1); 

  Serial.print( analogRead(ypin));
  Serial.print("\t");
  //add a small delay between pin readings.  I read that you should
  //do this but haven't tested the importance
    delay(1); 

  Serial.print( analogRead(zpin));
  Serial.print("\n");  // delay before next reading:
  delay(sampleDelay);
}

A sketch doesn’t get much simpler than this.  Once you build your circuit and upload this sketch, open up the serial monitor and you should start seeing data that looks something like this:

512  506  620
512  506  620
513  506  620
...

The higher voltage coming off of the z pin (the third column) is measuring the acceleration of gravity: 1 G in (almost) the positive z direction.  Flip the breadboard over and you’ll see something like this:

515  506  413
516  508  416
515  508  411
...

Now the z-pin gives a low voltage indicating the acceleration of gravity is now in the negative z direction.  If you are holding it in your hand, you’ll see the values bounce around a lot more than they do when it is sitting on a table.  Flip it around, tilt it different ways, shake it.  See what happens.

4. Calibrate the input

Now that you have the basic circuit up and running, you can see how tilt and acceleration are changing the voltages coming  out of your accelerometer, but things aren’t quite right.  What exactly do those numbers mean?

Reading the ADXL335 datasheet we see that on 3.3V power, we should expect an axis to read 1.65V when it has zero acceleration, and the voltage should typically change by 330 mV per G of acceleration.  The signal from our analog to digital converter gives us a number from 0 to 1023.   I’ll call these “ADC units”.  0V maps to 0 ADC units, 3.3V maps to 1023 ADC units and I assume it is linear in between.

This means that zero acceleration on an axis should give us a reading of 512 ADC units on the pin for that axis.  Also, a change of 1 ADC unit in our signal corresponds to a voltage difference of 3.3V/1023 ADC units = 3.226 mV/ADC unit.  Since the datasheet says 1G typically corresponds to  330 mV voltage difference, we expect that

330 mV/G = 330 mV/G × (1023 ADC units) / 3.3 V = 102.3 (ADC units)/G

We can use this to transform our signal into Gs.  To do it, change your loop() routine to look like this

void loop()
{
  int x = analogRead(xpin);

  //add a small delay between pin readings.  I read that you should
  //do this but haven't tested the importance
    delay(1); 

  int y = analogRead(ypin);

  //add a small delay between pin readings.  I read that you should
  //do this but haven't tested the importance
    delay(1); 

  int z = analogRead(zpin);

  //zero_G is the reading we expect from the sensor when it detects
  //no acceleration.  Subtract this value from the sensor reading to
  //get a shifted sensor reading.
  float zero_G = 512.0; 

  //scale is the number of units we expect the sensor reading to
  //change when the acceleration along an axis changes by 1G.
  //Divide the shifted sensor reading by scale to get acceleration in Gs.
  float scale = 102.3;

  Serial.print(((float)x - zero_G)/scale);
  Serial.print("\t");

  Serial.print(((float)y - zero_G)/scale);
  Serial.print("\t");

  Serial.print(((float)z - zero_G)/scale);
  Serial.print("\n");

  // delay before next reading:
  delay(sampleDelay);
}

With this sketch, now you’ll get serial output that looks something like this:

0.00	-0.05	1.06
0.00	-0.05	1.06
-0.01	-0.05	1.06
0.00	-0.05	1.06

There is very little acceleration in the x and y directions, and about 1G of acceleration in the z direction: this is the acceleration of gravity and it is about what we expect.

Now turn it over, and you’ll see something like this:

0.02	-0.03	-0.96
0.05	-0.08	-0.96
0.05	-0.03	-0.95
0.06	-0.06	-0.95

Again there is little acceleration in the x and y directions, and about -1G in the z direction, just what we expect.

This isn’t bad, but don’t we really want to see readings like “0.00  0.00  1.00″?  The readings we are getting have magnitudes that are not equal to 1.00 and the magnitude seems to depend on the orientation of the device.  This suggests that the zero-G reading and the scale factor we got from the datasheet aren’t quite right.

It turns out we can do much better with an empirical calibration, but that is the subject of another post.

Wrap-up

Hopefully this is enough to get you up and running with the ADXL335 on the Arduino.  Now go out and make something!

About these ads

About Rolfe Schmidt

No matter how much time I have, I can use it all with my wife and kids, running, or playing mathematician.
This entry was posted in Electronics, How To and tagged , , . Bookmark the permalink.

36 Responses to Getting Started with Accelerometers and Micro-controllers: Arduino + ADXL335

  1. XSC says:

    Thank you sooo much !!
    This is the BEST post I found about the ADXL335, is a great tutorial.

    Now im going to buy this accelerometer and make my own experiments. Thanks again for sharing your work.

    • You’re welcome, I’m glad it was helpful. Hopefully I’ll get my act together and write a few more follow-up posts soon: I’ve been playing around a lot with calibration and I’ve been trying some different sensors too.

      If you run into any troubles with it, feel free to ask. I like figuring these things out. Have fun!

  2. bruno says:

    congratulation, it worked at once !!!

  3. Hello says:

    Thank you very much! This is a super tutorial!

  4. Suresh Jonna says:

    Hi,

    Will ADXL335 work with this board(Arduino UNO)>>>>>http://nskelectronics.com/aurdino_uno_.html

    Kindly reply soon.

  5. Suresh Jonna says:

    I am following this post.

  6. amir says:

    Great intro – Thanks. just received my Arduino & ADXL335 and ready to do the soldering and trying out your code.

  7. Glen says:

    Great Job. I have the newer version of the ADXL-335, but was able to follow along perfectly. There’s a separate pinout for AREF on my board.

  8. Brooks says:

    I was at EXACTLY the same place. Soldering? A_ref? And yeah, I’m a good programmer who can do those 3 things. Thanks for making my day!

  9. timothy says:

    Hi Rolfe Schmidt,

    I’m glad i found your post.
    So is this the whole programming code that allows be to start measuring the acceleration?
    If i hold it up, the accelerometer will show something like X=0,y=0 and z=1.
    Then if i let it to drop, when it reach terminal velocity, will it show 0 acceleration?
    -which means x=0,y=0,z=0.

    I want to do a drop test and therefore will require to plot total acceleration vs time graph (half sine wave). How do i go about doing it?

    I apologize for asking too many question.

    Thank you.

    Yours Sincerely,
    timothy

    • C says:

      The value of z doesn’t mean z-coordinate but *acceleration* in the direction of the z-axis. After dropping the device on the flat surface, if it doesn’t flip to its back, it will again show the same as when holding it up (z = 1). Because the only acceleration is going to be Earth’s gravitation (1 g) in the direction of the z-axis.

  10. dxtr says:

    Thank you so so much my friend , that was very helpful :)
    but tell me , the datasheet says 1G typically corresponds to 330 mV voltage difference, but only with Vs = 3.6V , how can i calcul the sensation for whatever Vs is ?

  11. Pingback: need clarification about adxl335

  12. Chris says:

    Hi,

    I think you should divide by 1024 right? Since 0 to 1023 has a total of 1024 value.

    • C says:

      No! Imagine you have only 2 bits for ADC (max value is 3) and 4 V:
      0 = 0 V
      1 = 4/3 V = 1.33 V
      2 = 8/3 V = 2.66 V
      3 = 4 V

      The distance between ADC values is 4/3 (maximum voltage/maximum value) and NOT 4/4 (maximum voltage/total values).

  13. Steve Gough says:

    Did you ever do the emprical calibration? We’ve worked on this a bit to sense tilt for our river models (Google “emriver”) — I could perhaps find the data. We like to get around 0.1 degree sensitivity, and these chips don’t seem capable of that, but I have a hard time understanding the specs on sensitivity. Thanks!

    • I’ve done a bit of calibration, but focused more on accuracy of the magnitude than of the angle. Based on my experience, 1 degree is no problem, 0.1 degree is a stretch but maybe. I presume you’ll be keeping the sensor still, so you may be able to filter the readings and do better.

      I would also consider an accelerometer/magnetometer combo viewed through a Kalman filter. The second sensor will help manage bias drift too.

  14. touseef says:

    hi great lesson. could you please tell me how would i get around changing these ‘G’ values into angles? its very important. i need to do this for my project. Thanks in advance.

    • To measure the tilt angle relative to the acceleration (usually just gravity), notice that if \theta is the tilt angle in the x direction then \sin(\theta) is the value you read from the x axis on the sensor.

      So the tilt is $\latex \sin^{-1}(x)$. You’ll do even better with \tan^{-1}(x/z).

  15. touseef says:

    could you please help me translate this into useful arduino code. i am really bad at programming. i would be forever in your debt.

  16. sana says:

    Can you please tell me how can i measure z axis up,down rotation. Using ADXL335 I could measure pitch and roll angle. But i dont no how to measure yaw angle. If i place a sensor in flat surface and rotate the sensor in yaw angle rotation , sensor does not gives me any change in value.

    my robot car instead of driving in straight line, it has angle deviation from straight line while travelling. so i wanted to measure the angle deviation.
    please any one help me in calculating yaw angle.

    https://developer.valvesoftware.com/w/images/7/7e/Roll_pitch_yaw.gif

    • You will want to use a magnetometer for that, or even better a magnetometer combined with an accelerometer. The yaw rotation is a rotation around the z axis, which is parallel to the acceleration or gravity. Yaw changes leave vectors on this axis invariant, so you’ll never detect them.

      Otoh the earth’s magnetic field is not parallel to the yaw axis, even though it is closer than you may think in many parts. But unless you live in Greenland, you’ll certainly be able to measure yaw changes with a magnetometer.

  17. Matt McBee says:

    Thank you so much. This is so helpful.

  18. Luca Neri says:

    Hi Rolfe Schmidt,
    I have a problem using this example.
    With the sensor in a fixed position, I obtain these variable values on the Serial Monitor:
    1.37 2.38 2.35
    3.85 4.39 3.74
    5.00 4.55 3.58
    2.69 1.67 1.67
    -0.52 -0.86 -0.20
    -0.83 -0.59 -0.13
    -0.27 0.52 0.93
    I’m not able to figure out what’s wrong with this sensor. Can you help me?
    Thank you.

  19. me says:

    Hi…….
    I want to know, is it possible if my result from this adxl335 got like this…
    473 435 532
    493 435 532
    491 435 533
    491 435 532
    494 435 532
    ………
    tq..

  20. afmoosa says:

    thank u for the code…

  21. Scamper says:

    369 370 460
    369 371 460
    369 371 461
    369 370 461
    ………………….
    I am getting this reading….for 3,3V supply
    what might have gone wrong?
    is there any problem with the sensors?

  22. izziecc says:

    YES! these are the vital accelerometer info that is missing. before anything happens you need to figure out what the fuck is coming out of your machine. THANKS!

  23. Scamper says:

    Hi…
    im getting a value like:
    369 370 460
    369 371 460
    369 371 461
    369 370 461
    ………………….
    is this ok?? :(

  24. imediahil says:

    hi, this is a great blog, your explanations are really clear, thanks so much for taking the time to post.

  25. Andrew says:

    This was great! Very helpful! Thanks for putting this on the web! I’m looking forward to reading about how you calibrated to get better zero values.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s