Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save john212/15ad4e677318fe365e7d to your computer and use it in GitHub Desktop.
Save john212/15ad4e677318fe365e7d to your computer and use it in GitHub Desktop.
Using an ADXL335 3-axis Accelerometer to Measure The Angle of Incline From the X,Y, and Z Axis with an Arduino
/**************************************************
Udemy Arduino Step-by-Step Course
Section 3 Interactive Lecture 15 Detecting Acceleration
Quiz 10 Question 2 (not graded, not for credit, fun only:-)
by J. Cantlin
December 25, 2015 Merry Christmas!
***************************************************/
/**************************************************
Description of Program
A 3-Axis accelerometer is used to measure the angle
of incline compared to a resting position (horizontal to floor).
The sensor is an ADXL335 made by Analog Devices, it is
a +- 3g x,y,z 3-axis accelerometer. The algortihm for determining
the angle of incline is from an Analog Devices data
sheet. Reference: Analog Devices Application Notes:
"Using an Accelerometer for Inclination Sensing" - AN-1057 Rev. 0
http://www.analog.com
NOTE: to use the accelerometer to measure the angle of incline,
it is assumed the only acceleration is dude to gravity, that is,
a constant 1 g in the minus Z axis. If the sensor is accelerating,
the measurement may not be accurate of even meaningful.
Green, yellow and red LEDs will display light
as the sensor is tilted, starting from green at zero tilt
and as the incline steepens, then from yellow to red
as the incline passes some arbitrary angle, say 30 degrees.
***************************************************/
/**************************************************
Summary of Arduino Uno Analog Pins Used:
A0 = ADXL335 X-axis Sensor
A1 = ADXL335 Y-axis Sensor
A2 = ADXL335 Z-axis Sensor
A3 =
A4 =
A5 =
***************************************************/
/**************************************************
Summary of Arduino Uno Digital Pins Used:
00 =
01 =
02 =
03 = Green LED
04 = Yellow LED
05 = Red LED
06 =
07 =
08 =
09 =
10 =
11 =
***************************************************/
/*********************************************************************
The analog "zero" readings for the x, y, and z axis were determined.
The x,y axes are in the horizontal plane, if you place the breakout
board flat on the table, the x axis will be defined as + to the right
and - to the left. The y axis will be defined as + away from you and
- towards you. The z axis is in the vertical plane and the z axis
will be defined as + up and - down. When flat, the g forces versus
measured analog readings for the sensor were:
+x = 0g = 262 analog reading for x-axis use 326+-66. 326=zero g
-x = 0g = 392 analog reading
+y = 0g = 263 analog reading for y-axis use 325+-66. 326=zero g
-y = 0g = 395 analog reading
+z = 0g = 286 analog reading for x-axis use 351+-67. 350=zero g
-z = 1g = 418 analog reading
***********************************************************************/
/**********************************************************************
The map funtion "maps" one range of values to another:
map(value, fromLow, fromHigh, toLow, toHigh).
The constrain function will limit the range to a specified minimum and maximum:
constrain(x, min, max).
To contrain the analog sensor reading from say 260 to 392 and map them to
-1 g to 1 g" for the x, y axis and 1 g to -1 g for the z axis.
(example) constrain(valX, 326,392);
(example) map(valX,260,392,0,66) //mapping uses integer values only.
Since the map function does not work with floats, a user defined
funtion called mapf is used to replace map. Reference:
http://dm.risd.edu/pbadger/PhysComp/index.php?n=Code.MapConstrain
*********************************************************************/
/**********************************************************************
math.h is included in the built-in Arduino libraries (part of avr-libc)
math.h includes atan2(y-coordinate, x-coordinate), this function uses
the sign of the x and y coordinates to determine the angle whose tangent
is y/x in radians between 0 and 2PI (0-360 degrees). Multiplying the
radian measure by 360/2PI or 180/PI converts it to degrees.
The math.h library "include" statement is not needed, and is provided for clarity.
***********************************************************************/
#include <math.h> //Auduino code library for math operations
int greenLED = 3; // assign digital pin to an LED
int yellowLED = 4; // assign digital pin to an LED
int redLED = 5; // assign digital pin to an LED
float valX, valY, valZ; //raw analog values for x, y, and z axis readings.
float accX, accY, accZ; //analog readings converted to acceleration, in g's.
float angleX, angleY, angleZ; //angle of inclination with x,y, and z axis.
float absAngleX, absAngleY, absAngleZ; //positive incline angles
void setup()
{//****start setup function****
//Serial.begin(9600); //set the serial port to 9600 baud if monitor is used.
//constrain analog x, y, z readings to actual measured ranges
constrain(valX,260,392);
constrain(valY,259,391);
constrain(valZ,284,418);
//declare LED pins as output.
pinMode(greenLED, OUTPUT);
pinMode(yellowLED, OUTPUT);
pinMode(redLED, OUTPUT);
//start with green LED on, yellow LED and red LED off.
digitalWrite(greenLED, HIGH);
digitalWrite(yellowLED, LOW);
digitalWrite(redLED, LOW);
}//****endof setup function****
void loop()
{//****start infinite loop****
//read the accelerometer x, y, and z axis values
valX = analogRead(0); // read analog input pin A0
valY = analogRead(1); // read analog input pin A1
valZ = analogRead(2); // read analog input pin A2
delay(10); // short delay to allow readings to stabilize
//map the analog sensor readings to a g value between -1 g to + 1 g
//to match the values in AN-1057, the z readings were reversed.
accX = mapf(valX,260.0,392.0,+1.0,-1.0); //user defined mapf function
accY = mapf(valY,259.0,391.0,+1.0,-1.0); //user defined mapf function
accZ = mapf(valZ,284.0,418.0,-1.0,+1.0); //user defined mapf function
//calculate the angle of inclination with each axis.
angleX = atan2(accX,(sqrt(pow(accY,2)+pow(accZ,2))))*(180/PI);
angleY = atan2(accY,(sqrt(pow(accX,2)+pow(accZ,2))))*(180/PI);
angleZ = atan2((sqrt(pow(accX,2)+pow(accY,2))),accZ)*(180/PI);
//use fabs() "f"loating point absolute value vs abs()
absAngleX = fabs(angleX);
absAngleY = fabs(angleY);
absAngleZ = fabs(angleZ);
//illuminate the green, yellow and red LEDs as aprropriate.
if (absAngleX < 15 && absAngleY < 15 && absAngleZ < 15)
{
digitalWrite(greenLED, HIGH);
digitalWrite(yellowLED, LOW);
digitalWrite(redLED, LOW);
delay(100);
}
else if (absAngleX < 30 && absAngleY < 30 && absAngleZ < 30)
{
digitalWrite(greenLED, LOW);
digitalWrite(yellowLED, HIGH);
digitalWrite(redLED, LOW);
delay(100);
}
else
{
digitalWrite(greenLED, LOW);
digitalWrite(yellowLED, LOW);
digitalWrite(redLED, HIGH);
delay(100);
}
/********************************************************************/
// Print data used for testing and debugging - comment out as needed.
// Serial.print("analog readings for x, y, z: ");
// Serial.print(valX, DEC); // print the acceleration in the X axis
// Serial.print(" "); // prints a space between the numbers
// Serial.print(valY, DEC); // print the acceleration in the Y axis
// Serial.print(" "); // prints a space between the numbers
// Serial.println(valZ, DEC); // print the acceleration in the Z axis
//
// Serial.print("accX ");
// Serial.println(accX,DEC);
// Serial.print("accY ");
// Serial.println(accY,DEC);
// Serial.print("accZ ");
// Serial.println(accZ,DEC);
//
// Serial.print("angleX ");
// Serial.println(angleX,DEC);
// Serial.print("angleY ");
// Serial.println(angleY,DEC);
// Serial.print("angleZ ");
// Serial.println(angleZ,DEC);
// delay(1000); // waitfor next reading
/********************************************************************/
}//****endof infinite loop****
/********************************************************************
//function mapf to mimic map function but it uses floating point numbers
*******************************************************************/
float mapf(float x_, float in_min, float in_max, float out_min, float out_max)
{//****start mapf function****
return (x_ - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}//****endof mapf function****
@Tim-Kern
Copy link

I am more of a beginner than your students, and my question is more rudimentary, but I hope you can help.
I need the tangents of X and Y. I'm using an ADXL345 through I2C to an Arduino MEGA2560.
Typical readouts as I hold the board level look like this:
Xa= -0.05 Ya= -0.05 Za= 0.97
Xa= -0.04 Ya= -0.05 Za= 0.97
Xa= 0.01 Ya= -0.08 Za= 0.97
Xa= 0.02 Ya= -0.10 Za= 0.97
Questions:

  1. What are the units of Xa and Ya?
  2. How can I get the tangents of the angles measured on the X and Y axes?
    Thank you.

@john212
Copy link
Author

john212 commented Nov 13, 2022

The units should be some fraction of g, the gravitational acceleration. If it was a perfect sensor (no such thing in reality) and were perfectly level it would measure o g in the x and y direction and -1 g in the z direction.

The formula for calculating the angle of inclination is explained here, see if this helps: https://www.hobbytronics.co.uk/accelerometer-info

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment