0

I´m trying to figure out how to calculate the inclination angle of head movement, just up-down movement, not moving right-left side. I have a wearable device (I guess the problem would be the same for mobile devices) with an accelerometer sensor and it is placed on my forehead.

So far, I think is better to leave the linear acceleration out and just work with the gravity acceleration. I´m reading and reading trying to understand better what exactly I´m looking for, but my brain is not maths material. In a starting position of standing still (stationary position), all the gravity acceleration falls into an axis, lets say X. When I start producing movement with my head, for instance moving my head down (like looking to the ground), the aceleration gravity does not fall only into an axis, but two axes (would be shared, for instace between X and Z). If I´m right and this is the right approach (is it?)...

  1. How can I calculate this angle without doing crazy maths?
  2. This problem is exactly the same than calculating the pitch angle of an accelerometer?
  3. Can I use for this raw data or I need to calibrated data?

To make it clear, let´s imagine that my device axes are placed in the same position than this photo and that in the starting position the gravity falls into X axis (landscape position).

enter image description here

EDIT

Using the following formulas for pitch and roll (thanks to @Nuclearman link)

Roll = atan2(Y, Z) * 180/M_PI; 
Pitch = atan2(X, sqrt(Y*Y + Z*Z)) * 180/M_PI

And this code I wrote:

/**
* Function to calculate the inclination angle or pitch of the head movement
*/
float calcInclinationAngle(int iDataPos){

  float xVal = fAccel[0][iDataPos];
  float yVal = fAccel[1][iDataPos];
  float zVal = fAccel[2][iDataPos];
  float pitch = 0;
  //Pitch in rad format
  pitch = atan2(xVal, sqrt(pow(yVal,2)+pow(zVal,2)));
  //Pitch in degrees
  pitch = pitch * 180/PI;
  return pitch;

I always get wrong angles. When the gravity force is entirely on the X axis, I get around 45 degrees (instead of 0) and if I move the device 180 degrees (just changing the gravity force signal), I get around 17-18 degrees. I have been playing with atan2 parameters, but the angles range is always the same (25-35 degrees). Just throwing a question...should I be working with calibrated data instead of raw data?

Edit 2

I have done some progress "cheating" a bit, due to I'm totally stuck. Now I normalize the data and instead of using atan, I do pitch = 1/sin(xVal), which actually gives me a range of 90 degrees which seems to fit with my device rotation (although for example it gives me 135 degrees instead of...45, but I "fix" that substracting 90 degrees to all the angles). Anyway, I need a 180 degrees range because at the moment moving backwards or forward does not make a difference in the obtained angles.

Edit adding some pictures and information

Calculating the pitch as pitch = atan2(xVal, sqrt(pow(yVal,2)+pow(zVal,2))) * (180/PI), I obtain the following angles. Just in case is useful, the accelerometer values (raw data) in the position 1 are: ACCX 2936 ACCY 2152 ACCZ 1883

Position 1 (gravity falls into X axis): 45-46 degrees

Position 2 (rotating aprox 45 from starting point): 38

Position 3 (rotating aprox 90 from starting point): 28

Position 4 (rotating aprox 180 from starting point): 18-19

Position 5 (> 180 < 360): 18-46.

enter image description here enter image description here height enter image description here enter image description here

SOLUTION

Just in case someone bumps into something similar in the future. The main problem was the range of the raw data. Once I mapped this into a [-1g, 1g] range and fixed a few things about the coordinates it worked.

Rafag
  • 719
  • 3
  • 11
  • 27
  • 1
    [This](http://stackoverflow.com/questions/3755059/3d-accelerometer-calculate-the-orientation) answer on calculating the orientation using a 3D accelerometer might be what you are looking for. I do believe you are indeed after the Pitch angle. However, you might need to offset the resulting angle so it makes sense for your purpose. – Nuclearman May 18 '14 at 06:18
  • Well, using these two formulas: Roll = atan2(Y, Z) * 180/M_PI; Pitch = atan2(X, sqrt(Y*Y + Z*Z)) * 180/M_PI; The angles that I get are not right. It seems like I only have a range of 25-30 degrees. For example, when the gravity force is falling into the X axis, I get an angle of 45-50 degrees or so (I guess 0 or 90 would be correct). Moving my device 90 degrees, I obtain around 20 degrees. No idea what's happening... – Rafag May 19 '14 at 11:46
  • 1
    In that case, you should probably include a few more diagrams of it in a specific position, what you expect to see, what you are actually seeing and the raw data from the accelerometer. Also, in the comments, it notes that you may need to use "atan2(-X, sqrt(Y*Y + Z+Z))" instead depending on the coordinate system used by the accelerator. Speaking of coordinate systems, the coordinate system may not match the coordinate system in the formula. A bit brute force, but you may have to try all permutations (including inverting the signs). You may also need to try both formulas. – Nuclearman May 19 '14 at 23:17
  • 2
    Also, is the head moving when you get the measurements? Movement of the head up and down is angular motion and angular motion results in additional acceleration forces. In that case, the measurements are almost certainly not purely based on gravity unless they can be filtered out somehow (seems unlikely). As noted before, a number of measurements at different angles would be helpful. You'd probably have to do several measurements, estimate the angular motion then remove that acceleration competent to get an estimate as to the gravity. Which is another question to ask about. – Nuclearman May 19 '14 at 23:30
  • At the moment I'm just trying to calculate the angles having the device on my hand (rotating up and down), so I guess we can assume there is no any other acceleration. About the coordinate system, I have pretty much tried all different permutations, but no luck. As long as I used the formulas above, I only get a range of 40 degrees top...instead of 360 degrees. As I said in my edits, using asin the behaviour of the rotation is good but I can only recognise 90 degrees. I'll edit my post in 5 minutes with some pictures and the angles I get. – Rafag May 20 '14 at 09:11
  • Post edited with some measurements – Rafag May 20 '14 at 10:04
  • I take it position 1 is where it's sitting on the table. That's a rather odd measurement indeed. In that position, one axis should be much higher than the others, but that isn't what the numbers are showing. All the numbers should be much closer than they appear if gravity is being ignored unless that accelerometer has much higher precision then I think it does. You might want to try orienting it to minimize the raw x, y and z values one at a time and taking a posting a picture of the three positions. It might just need to be oddly oriented. Ideally, use something that can hold it in place. – Nuclearman May 20 '14 at 18:56
  • Just to let you know, the problems came due to the range of the raw data, once I mapped them to -[-1g, 1g] and fix a few things with the help of @Spektre it works. Thanks anyway for your help! – Rafag May 21 '14 at 13:55

1 Answers1

1

Measure just gravity orientation. there are two approaches I know of

1.use smooth (FIR) filter to filter out quick changes

  • for example remember last N measurements
  • and output their average
  • this is easy and continuous but not precise

2.check for acceleration vector size

  • and ignore all measurements where it does not match the gravity

    a=sqrt( ax^2 + ay^2 + az^2 )
    if (fabs(a*scale-9.81)>0.1) ignore...
    
  • where a is size of acceleration vector

  • (ax,ay,az) is measured acceleration vector (local to your device)
  • scale is scale of your accelerometer to convert a value to actual units like [m/s^2] or [N/kg]
  • device accelerometers are usualy already in [g] so the scale is 9.81
  • 9.81 is the gravity in the area of measurement
  • 0.1 is accuracy of acceleration size check (change it to your needs)
  • this approach is a bit slower
  • and not continuous because during acceleration will not measure the output (can use last valid output)
  • but it is much more precise

Now the formulas should work, from what I read your axises are

  • x - up,down
  • y - left,right
  • z - forward,backward
  • do not know the orientation so just negate output angle if i hit it the wrong way

axises

  • green is the gravity
  • blue is measured values
  • red is your pitch angle (ang)

    ang=asin(az*scale/9.81)
    
  • do not forget to avoid using asin with parameter out of range < -1.0 , +1.0 > !!!

Spektre
  • 49,595
  • 11
  • 110
  • 380
  • Great information!.About measuring just gravity, at the moment I'm just trying to calculate the angles with the device over a table or my hand, so I guess we can assume there is no linear acceleration (doing the filtering you commented I guess will be next step). The figure is great, very good representation of my problem. Two things...are you assuming my data is calibrated? I'm working with raw data. And second, to get the pitch...wouldnt be ang = asin(ax*...)? Or for this case is the same than using z value? Anyway, using asin...there is no way of obtaining more than 90 degrees right? – Rafag May 20 '14 at 09:27
  • asin gives you < -90 , +90 > degrees depending on the az sign and value. Allways use just Z-axis because that is the direction you want not the x,y sides (they change with roll) !!! you must calibrate your device (scale for each axis to match ~gravity 9.81, ... usually is the same for all axises) scale(axis)=9.81/max(|a(axis) value|) – Spektre May 20 '14 at 10:47
  • But once I have the scale value for each axis...how I convert every raw data sample to calibrated values? Sorry but I don't get where I'm heading. So...I definitely can't get the pitch without using calibrated data? – Rafag May 20 '14 at 11:33
  • Scale = 9.81/2900; (2900 is the max value for any axis), and then...pitch = asin(zVal*scale/9.81) is what you mean? – Rafag May 20 '14 at 11:47
  • calibrated = 9.81 * raw / 2900. if the max value is very different for other axises then you need to have separate calibration scales. If they are +/- the same then single scale suffice. also you can do this: ang=asin(raw_az/2900); – Spektre May 20 '14 at 12:26
  • Thanks Spektre, I've done it that way but the angle thing does not works...one thing, I don't know if the raw data of my device is "tricky" but when gravity is falling into an axis, it shows values near 1 (good), but if I turn it 180 degrees, it shows 0.3 (I would expect something like -1). I mean, the "range" is 0.3-1 – Rafag May 20 '14 at 13:06
  • 1
    in that case calibrated = 9.81*((2.0*(raw-min)/(max-min))-1.0) where min and max are your min and max raw values ... – Spektre May 20 '14 at 13:58
  • Thats great, now it works! Thanks so much! I get a correct (according with the applied rotations) angle measurement using Pitch = atan2(X, sqrt(Y*Y + Z*Z)) * 180/M_PI or Pitch = atan2(Z, sqrt(X*X + Y*Y)) * 180/M_PI, within a range of 180 degrees. The only difference between these two is the "starting" angle measure. Which one should I use? I know you said Z cause X and Y are affected by the roll but...however I don't see the difference. Besides, my roll Roll = atan2(Y, Z) * 180/M_PI; seems to have a strange behaviour. With roll I could track right-left movement? – Rafag May 21 '14 at 09:45
  • it is almost the same the only thing is that sqrt(X*X+Z*Z) is slower to compute. asin has also 180deg range < -90 , +90 > – Spektre May 21 '14 at 09:56
  • I forgot to say that I'm not using asin(xVal) or asin(zVal) cause it does not give me any angles (only gives me some when the device is lying on the table). – Rafag May 21 '14 at 09:56
  • if mine picture is correct then Pitch = atan2(Z, sqrt(X*X + Y*Y)) * 180/M_PI – Spektre May 21 '14 at 10:00
  • The only difference is that the device is in different orientation, I mean, landscape (like the picture with the position 1) – Rafag May 21 '14 at 10:03
  • I drawed it as landscape therefore x is up,down instead of left,right. the black box is viewed from side but it is landscape oriented – Spektre May 21 '14 at 10:15
  • Great, all clear, in the position 1 using asin(z) I obtained 0 degrees for pitch, which I assume is correct. However, I don't know if I understand roll correctly. In the position 1, I want to rotate the device to right or left direction, expecting to get that movement angle, but I just obtain unpredictible angles (Using atan2(yVal, zVal) * 180/PI, being yVal and zVal calibrated values). – Rafag May 21 '14 at 10:52
  • as I see it roll is in your case atan2(ay,ax) without any az !!! of course if |az|=9.81 then roll is undefined – Spektre May 21 '14 at 12:00
  • great, that's the solution. Thank you soo much! You totally saved me :) For someone a bit dyslexic all this axes stuff can be confusing as hell. – Rafag May 21 '14 at 13:50