Last active
November 13, 2022 19:45
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/************************************************** | |
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**** | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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