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:
- Solder pins to the breakout board or do something else to get a good connection.
- Build the circuit with 3.3V power and AREF to normalize the analog input.
- Write a basic sketch.
- 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.
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:
This image was produced with Fritzing. Here is what my circuit looks like in real life:
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:
- Initialize serial communication
- Tell the analog-to-digital converter to use an external reference voltage (which comes in on the AREF pin).
- Set up our input pins.
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!
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!
congratulation, it worked at once !!!
Thank you very much! This is a super tutorial!
Hi,
Will ADXL335 work with this board(Arduino UNO)>>>>>http://nskelectronics.com/aurdino_uno_.html
Kindly reply soon.
I’m sure it will. I haven’t used that exact board, but the circuit in this post was tested on a very similar Arduino Uno. The ADXL335 is pretty simple to read as long as you have 3 analog pins free.
Thanks Rolfe
I am following this post.
Great intro – Thanks. just received my Arduino & ADXL335 and ready to do the soldering and trying out your code.
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.
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!
My pleasure!
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
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.
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 ?
Pingback: need clarification about adxl335
Hi,
I think you should divide by 1024 right? Since 0 to 1023 has a total of 1024 value.
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).
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.
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 is the tilt angle in the x direction then 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 .
could you please help me translate this into useful arduino code. i am really bad at programming. i would be forever in your debt.
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.
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.
Thank you so much. This is so helpful.
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.
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..
That looks well within reason. Flip it over, put it on its side, etc. and you should start to see what those numbers mean.
TQ… Rolfe Schmidt,
I want to know, the reason why, the VCC of ADXL335 connect to the VREF…
I am still learn about Electronic…
tq..
me
thank u for the code…
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?
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!
Hi…
im getting a value like:
369 370 460
369 371 460
369 371 461
369 370 461
………………….
is this ok?? 😦
hi, this is a great blog, your explanations are really clear, thanks so much for taking the time to post.
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.
Thanks a lot you’re good!
Have you tried any kind of filtering for the ADXL335 data?
I’ve used Kalman filters to remove drift from these and other sensors – they are very effective. Convolutional filters would probably only make sense for certain applications, but I haven’t thought very hard about it.
At first glance I can say that a low-pass filter on a sensor experiencing non-linear changing acceleration (e.g. rotating in a gravitational field) is going to give you bias. But if the thing is sitting still it should improve your signal.
Caveat lector: It has been a while since I’ve worked with these.