cancel
Showing results for 
Search instead for 
Did you mean: 

MEMS 3-axis accelerometer

pswenson
Associate II
Posted on October 25, 2008 at 22:36

MEMS 3-axis accelerometer

7 REPLIES 7
pswenson
Associate II
Posted on May 17, 2011 at 12:48

I'm using the LIS3LV02DL 3-axis MEMS accelerometer as a tilt sensor with an STM32. The X-axis angle is calculated by the formula:

angle = arctan(Ax/sqrt(Ay^2 + Az^2)), where Ax,Ay,Az are the acceleration values from the accelerometer. Similar deal for the Y-axis.

This all works fine. However, due to space constraints, the target PCB is mounted at an angle within its enclosure. Is there a good way to compensate/correct for the mounting offsets on all axes? Currently, I have a ''level'' function, where I set the enclosure on a level surface, read the 3 axes, calculate the angle for each axis, and then use those angles as correction values to calculate ''relative'' angles. This works, except at the limits, where it will never reach 90 degrees going one way or it'll go past 90 degrees going the other way. Is there a better way?

lanchon
Associate II
Posted on May 17, 2011 at 12:48

arctan(Ax/sqrt(Ay^2 + Az^2)) gives the angle of the vector with the YZ plane, calling the X direction ''positive''. it fails when the vector is null or parallel to X; use atan2(Ax, sqrt(Ay^2 + Az^2)) to avoid that problem.

a few basics:

lets call any vector which modulus is 1 a ''versor''. a versor indicates a direction but not a modulus.

vector acceleration measurements taken on earth with static sensors should be versors when scaled by (1/g), but they won't be because of errors.

normalization obtains a versor from a non-null vector, with the same direction and sense. to normalize v into versor N(v):

-calculate the modulus m(v)=sqrt(vx^2 + vy^2 + vz^2)

-scale each coordinate of v by (1/m(v))

so N(v) = (1/m(v)) * v for v != 0

the dot product of two vectors is a scalar (simple number) defined like this:

v1 . v2 = v1x*v2x + v1y*v2y + v1z*v2z

so: m(v) = sqrt(v . v)

and it's commutative: a . b = b . a

it's a property of the dot product that the product of two versors is the cosine of the angle between them. so if v1 and v2 are versors, the angle in radians between them is:

acos(v1 . v2)

now on to your question:

let v be a tri-axial vector measurement of acceleration using a static sensor. check that m(v) is close to 1g. (if not, the sensor is not static and tilt info is not reliable, so you abort.) normalize it into versor vn:

vn = N(v)

lets call x the versor whose components are (1, 0, 0). x is a versor that has the direction of the positive X axis.

so the angle between v and the X axis (0 to pi) is:

ax = acos(vn . x)

note that since x = (1, 0, 0), vn . x = vnx, where vnx is simply the first component of versor vn. so:

ax = acos(vnx)

also, if you prefer the angle between v and the YZ plane (-pi/2 to pi/2) calling the X direction ''positive'' (like in your equation), then that angle is:

ayz = asin(vn . x) = asin(vnx)

note that with the formula a = asin(N(v) . d) you can calculate the angle between a vector v and the plane perpendicular to any versor d, calling the direction of the versor ''positive''. (d must be a VERSOR!) (if d is one of the x,y,z axis versors, then the calculation can be simplified a bit, as shown.)

so...

calibrate your sensor by taking a measure of the ''up'' direction: leave it flat and still and measure vector u. m(u) should be around 1g, otherwise discard u. then normalize u:

un = N(u)

now you're ready to measure tilt. measure vector v. discard it if m(v) is not around 1g. then normalize v:

vn = N(v)

then the tilt angle (0 to pi) relative to the calibrated ''up'' direction is simply:

acos(un . vn)

where 0 means leveled and any deviation increases the angle.

but you probably want more of a joystick behavior. you can establish x and y directions by calibrating on two orthogonal sides. (xn . yn should be close to zero if it's true that x and y they are nearly orthogonal. the same goes for xn . un and yn .un, but you don't really need to measure u for this calculation.)

in this case, the angles against planes YZ and XZ (-pi/2 to pi/2) are:

tiltx = ayz = asin(vn . xn)

tilty = axz = asin(vn . yn)

which is probably what you want.

pheew! I thought this post was going to be much shorter! 🙂

obtronix
Associate II
Posted on May 17, 2011 at 12:48

Your always going to have problems at 90 degrees with euler equations.

I use quaternions to get around the problem (but doesn't eliminate it) for inertial navigation computations in 3D space. See

http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/index.htm

but I don't think you need that.

pandoraems
Associate II
Posted on May 17, 2011 at 12:48

to the OP

After you play around with it, let me know if you had similar problems with acceleration data gathered from the chip that i had

here is my story

http://forum.sparkfun.com/viewtopic.php?t=12525&highlight=

pswenson
Associate II
Posted on May 17, 2011 at 12:48

Thanks for the feedback.

pandoraems,

That is an odd problem. I did all of my prototyping with the DQ part and dropped the DL on my target PCB. I'm using the exact same code for both. The DQ works fine, but none of the four DL parts are working at the moment. In other words, it might not be you...

armaniake
Associate II
Posted on May 17, 2011 at 12:48

Hi pandoraems,

Did you set the BDU bit to '1' inside CTRL_REG2? This will make sure no temporal discontinuity will occur.

Regards

pandoraems
Associate II
Posted on May 17, 2011 at 12:48

Quote:

On 25-10-2008 at 00:14, Anonymous wrote:

Hi pandoraems,

Did you set the BDU bit to '1' inside CTRL_REG2? This will make sure no temporal discontinuity will occur.

Regards

yes, i've tried this with no luck

i actually found the workaround for this problem. One just needs to simply shift the overflow point on the LSB by 0xd0. I.e do this: Real_LSB = (LSD+0xd0)&0xff

this modification had brought the overflow point to that of increment/decrement point of the MSB - no more jerkiness