Is there any way to remove the small bias along the gravity axis in the accelerometer data - iphone

Similar to this question:
CMDeviceMotion userAcceleration drift
I'm using CMDeviceMotion.userAcceleration in iOS5 SDK to plot its x, y, z components over time. Like the above post, I see z acceleration component shows always small positive values (0.005 - 0.015) while x and y components are centering along zero (-0.005 - 0.005) when my iPhone 4s is sitting on a flat surface.
This small bias keeps adding up to the estimated velocity (which I compute by integrating the acceleration data) even when my phone is not moving a bit. Is there any known way to remove this bias from the accelerometer data? I cannot simply subtract the bias from z component because it seems that the bias spreads over x y and z along the gravity axis if the device is in some arbitrary orientation.
I know that the data in CMDeviceMotion.userAcceleration has already factored out the gravity using Gyro data but wonder if there is any effective way to remove this residual bias?

First, you need some external reference that does not drift such as GPS. Then you have to perform sensor fusion (Kalman filter comes to mind). Otherwise you cannot remove the bias and the integration error will grow indefinitely.
UPDATE: You cannot get relative displacement just by integrating the acceleration, see my answer to Android accelerometer accuracy (Inertial navigation). However, I give some examples there what you actually can do.
If you check my answer you will see that it is the gyro white noise that makes the integration hopeless.

Old question, but I wanted to share some insight. Part of the bias in the accelerometers actually does not come from any inaccuracies in the sensors, but from an oversight in the calculations that Apple does. The calculations assume that gravity always is 1 G (which is by definition 9.80665 m/s2). Any left-over must then be user acceleration.
However, gravity varies slightly all over the world. If the gravity in your area is not exactly 9.80665 m/s2, then there will be a small bias in the user acceleration, which is detectable with a low-pass filter. Such a bias can removed with the following calculation:
- (void) handleDeviceMotion:(CMDeviceMotion *)m atTime:(NSDate *)time
{
// calculate user acceleration in the direction of gravity
double verticalAcceleration = m.gravity.x * m.userAcceleration.x +
m.gravity.y * m.userAcceleration.y +
m.gravity.z * m.userAcceleration.z;
// update the bias in low pass filter (bias is an object variable)
double delta = verticalAcceleration - bias;
if (ABS(delta) < 0.1) bias += 0.01 * delta;
// remove bias from user acceleration
CMAcceleration acceleration;
acceleration.x = m.userAcceleration.x - bias * m.gravity.x;
acceleration.y = m.userAcceleration.y - bias * m.gravity.y;
acceleration.z = m.userAcceleration.z - bias * m.gravity.z;
// do something with acceleration
}
Mind you, even with that bias removed, there is still a lot of noise, and there could also be a manufacturing bias different for each accelerometer chip. Therefore, you will still have a hard time deriving velocity and certainly position from this.

Thanks Ali for updating your answer and other references. They certainly helped my understanding on this issue (and I was surprised to see how many people are interested in this issue). I may sound a bit stubborn but I still think I didn't find the answer for my original question from anywhere. Let's forget about integration now. With more experiments I see some constant biases (though even smaller) on x and y axes as well when I averaged the user acceleration data over time. I was just wondering if there's any way to remove these biases from "user" acceleration data which I get from iOS5 CMDeviceMotion. If they were caused by the white noise of the gyroscope in the process of filtering out the gravity, I guess we may see random noise in the user accelerometer data but not those biases. But based on my impression so far, it seems that those biases were caused by the limited "accuracy" of both accelerometer and gyroscope and there's nothing we can do about that although I'm not 100% sure. I was trying to put my impression in comment (not in answer section) but SO didn't allow because it was too long but I was wondering how many people would back up my impression by voting so I decided to put it in answer section... Sorry if I was rambling a bit.

Related

Drifting yaw angle after moving fast

In my current project I ran into trouble regarding the quaternion provided by Core Motion's CMAttitude. I put the iPhone 5 (iOS 6.0.1) at a well defined start position. Then I start to move the device quickly around like in a fast pacing game. When I return to the start position after 10-30 seconds the reported yaw angle differ from the start position for 10-20 degrees (most of the time ≈11°).
I used the old (and sadly no longer available) Core Motion Teapot sample to validate the effect. The Euler Angles for logging are read directly from CMAttitude:
NSLog(#"pitch: %f, roll: %f, yaw: %f", attitude.pitch * 180 / M_PI, attitude.roll * 180 / M_PI, attitude.yaw * 180 / M_PI);
I found this on two different iPhone 5 devices manufactured at different times in different factories. But really weird is that my iPhone 4, running iOS 5.1.1, is working as expected. It seems to me an iOS bug and I filed a bug report already, but on the other hand I can hardly imagine that nobody had yet stumbled upon it. I suspect it might has to do with the redesigned Core Motion API. Starting with version 5 the magnetometer (compass) is considered for sensor fusion as well. Console shows that bias estimations from locationd are provided to CoreMotion:
locationd[41] <Notice>: GYTT inserted: bias,-0.196419,1.749323,-1.828088,variance,0.002644,0.004651,0.002527,temperature,31.554688
My question(s): Is there chance to block magnetometer readings when using Device Motion? I tried deactivating location services but it doesn't affect Core Motion. If not possible, what is the alternative / workaround, Accelerometer based gravity estimation?
PS: As we are dealing with quaternion based models this is not related to Gimbal Lock
EDIT:
After doing some more measurements it seems clear that only yaw is affected. Pitch and roll show deviations within tolerance (<= 1°) while yaw is drifting regardless of the starting position. CMDeviceMotion.gravity appears to be clean too.
EDIT (2):
I could reproduce the problem with the MotionGraphs sample attached to recent XCode versions. The yaw graph is reproducibly drifting away from origin.
Not the definitive solution but at least a workaround for my own question (I leave it as unanswered to invite you). It turned out that at least DeviceMotion.gravity is not affected by the bug. So I decided to redesign this pretty simple part of motion detection and use arcsin (gravity.x/||gravity||) for moving the main player character to the side when tilting the device.
This is definitely the second best solution as it destroys information about the full rotation status contained in a quaternion. I decided to it that way for strategical considerations:
I think most developers do tilt motion detection with the gravity vector rather than CMAttitude.quaternion because most people are not that amused about quaternion maths ;-) Thus any future bugs related to the gravity vector will probably be fixed during the beta phase because of a larger number of users.
If it is a software bug and not related to hardware issues, what I assume, and if the bug will be fixed ASAP, there is still a number of devices that might not get updated for what reason ever. Thus the risk that a potential future customer will run into trouble is small but > 0. So the second best solution might be sometimes the best.
I've done something similar in my own code and found the same z-axis rotational drift (yaw). I've applied a balanced filter. At each motion manager time interval, I grab the current quaternion (z-component) and then save that after calculations as oldZ, for use in the next set of calculations. My filter simply balances the NEW z value with the z value immediately preceeding it, preventing it from moving too much too quickly. Depending on your hardware and the exact tolerance in your program, you can manage drift quite well in this way. You will see the gyro drift slightly, but then begin to be corrected as the filter continues to act. My filter looks something like this and prevents more than 0.5 degree of "stray":
filtZ = 0.65 * oldZ + 0.35 * z;
The 0.65 and 0.35 values were determined experimentally and I would advise you to play with those as you have time. Output will still be scaled 0-1 and can then be utilized in the same way you've been doing (or re-introduced to the quaternion if you must retain all 4 dimensions throughoutf).

Calculating Lean Angle with Core Motion

I have a record session for my application. When user started a record session I start collecting data from device's CMMotionManager object and store them on CoreData to process and present later. The data I'm collecting includes gps data, accelerometer data and gyro data. The frequency of data is 10Hz.
Currently I'm struggling to calculate the lean angle of device with motion data. It is possible to calculate which side of device is land by using gravity data but I want to calculate right or left angle between user and ground regardless of travel direction.
This problem requires some linear algebra knowledge to solve. For example for calculation on some point I must calculate the equation of a 3D line on a calculated plane. I am working on this one for a day and it's getting more complex. I'm not good at math at all. Some math examples related to the problem is appreciated too.
It depends on what you want to do with the collected data and what ways the user will go with that recording iPhone in her/his pocket. The reason is that Euler angles are no safe and especially no unique way to express a rotation. Consider a situation where the user puts the phone upright into his jeans' back pocket and then turns left around 90°. Because CMAttitude is related to a device lying flat on the table, you have two subsequent rotations for (pitch=x, roll=y, yaw=z) according to this picture:
pitch +90° for getting the phone upright => (90, 0, 0)
roll +90° for turning left => (90, 90, 0)
But you can get the same position by:
yaw +90° for turning the phone left (0, 0, 90)
pitch -90° for making the phone upright (-90, 0, 90)
You see two different representations (90, 90, 0) and (-90, 0, 90) for getting to the same rotation and there are more of them. So you press Start button, do some fancy rotations to put the phone into the pocket and you are in trouble because you can't rely on Euler Angles when doing more complex motions (s. gimbal lock for more headaches on this ;-)
Now the good news: you are right linear algebra will do the job. What you can do is force your users to put the phone in always the same position e.g. fixed upright in the right back pocket and calculate the angle(s) relative to the ground by building the dot product of gravity vector from CMDeviceMotion g = (x, y, z) and the postion vector p which is the -Y axis (0, -1, 0) in upright position:
g • x = x*0 + y*(-1) + z*0 = -y = ||g||*1*cos (alpha)
=> alpha = arccos (-y/9.81) as total angle. Note that gravitational acceleration g is constantly about 9.81
To get the left-right lean angle and forward-back angle we use the tangens:
alphaLR = arctan (x/y)
alphaFB = arctan (z/y)
[UPDATE:]
If you can't rely on having the phone at a predefined postion like (0, -1, 0) in the equations above, you can only calculate the total angle but not the specific ones alphaLR and alphaFB. The reason is that you only have one axis of the new coordinate system where you need two of them. The new Y axis y' will then be defined as average gravity vector but you don't know your new X axis because every vector perpedicular to y' will be valid.
So you have to provide further information like let the users walk a longer distance into one direction without deviating and use GPS and magnetometer data to get the 2nd axis z'. Sounds pretty error prone in practise.
The total angle is no problem as we can replace (0, -1, 0) with the average gravity vector (pX, pY, pZ):
g•p = xpX + ypY + zpZ = ||g||||p||*cos(alpha) = ||g||^2*cos(alpha)
alpha = arccos ((xpX + ypY + z*pZ) / 9.81^2)
Two more things to bear in mind:
Different persons wear different trowsers with different pockets. So the gravity vector will be different even for the same person wearing other clothes and you might need some kind of normalisation
CMMotionManager does not work in the background i.e. the users must not push the standby button
If I understand your question, I think you are interested in getting the attitude of your device. You can do this using the attitude property of the CMDeviceMotion object that you get from the deviceMotion property of the CMMotionManager object.
There are two different angles that you might be interested in the CMAttitude class: roll and pitch. If you imagine your device as an airplane with the propeller at the top (where the headphone jack is), pitch is the angle the plane/device would make with the ground if the plane were in a climb or dive. Meanwhile, roll is the angle that the "wings" would make with the ground if the plane were to be banking or in mid barrel roll.
(BTW, there is a third angle called yaw that I think is not relevant for your question.)
The angles will be given in radians, but it's easy enough to convert them to degrees if that's what you want (by multiplying by 180 and then dividing by pi).
Assuming I understand what you want, the good news is that you may not need to understand any linear algebra to capture and use these angles. (If I'm missing something, please clarify and I'd be happy to help further.)
UPDATE (based on comments):
The attitude values in the CMAttitude object are relative to the ground (i.e., the default reference frame has the Z-axis as vertical, that is pointing in the opposite direction as gravity), so you don't have to worry about cancelling out gravity. So, for example, if you lie your device on a flat table top, and then roll it up onto its side, the roll property of the CMAttitude object will change from 0 to plus or minus 90 degrees (+- .5pi radians), depending on which side you roll it onto. Meanwhile, if you start it lying flat and then gradually stand it up on its end, the same will happen to the pitch property.
While you can use the pitch, roll, and yaw angles directly if you want, you can also set a different reference frame (e.g., a different direction for "up"). To do this, just capture the attitude in that orientation during a "calibration" step and then use CMAttitude's multiplyByInverseOfAttitude: method to transform your attitude data to the new reference frame.
Even though your question only mentioned capturing the "lean angle" (with the ground), you will probably want to capture at least 2 of the 3 attitude angles (e.g., pitch and either roll or yaw, depending on what they are doing), potentially all three, if the device is going to be in a person's pocket. (The device could rotate in the pocket in various ways if the pocket is baggy, for example.) For the most part, though, I think you will probably be able to rely on just two of the three (unless you see radical shifts in yaw throughout the course of a recording session). So for example, in my jeans pocket, the phone is usually nearly vertical. Thus, for me, pitch would vary a whole bunch as I, say, walk, sit or run. Roll would vary whenever I change the direction I'm facing. Meanwhile, yaw would not vary much at all (unless I do kart-wheels, which I can't!). So yaw can probably be ignored for me.
To summarize the main point: to use these attitude angles, you don't need to do any linear algebra, nor worry about gravity (although you may want to use this for other purposes, of course).
UPDATE 2 (based on Kay's new post):
Kay just replied and showed how to use gravity and linear algebra to make sure your angles are unique. (And, btw, I think you should give the bounty to that post, fwiw.)
Depending on what you want to do, you may want to use this math. You would want to use the linear algebra and gravity if you need a standardized way of "talking about" and/or comparing attitudes over the course of your recording session. If you just want to visualize them, you can probably still get away with not using the increased complexity. (For example, visualizing (pitch=90, roll=0, yaw=0) should be the same as visualizing (pitch=0, roll=90, yaw=90).) In my approach above, while you could have multiple ways of referring to the "same" attitude, none of them is actually wrong, per se. They will still give you the angles relative to the ground.
But the fact that the gyroscope can switch from one valid description of an attitude to another means that what I wrote above about getting away with only 2 of the 3 components needs to be corrected: because of this, you will need to capture all three components, no matter what. Sorry.

What exactly does the iPhone accelerometer measure?

The apple documentation for UIAcceleration class says,
"When a device is laying still with its back on a horizontal surface, each acceleration event has approximately the following values:
x: 0
y: 0
z: -1"
Now, I am confused! How can the acceleration be non-zero, when you clearly say the "device is laying still"?
UPDATE
Judging by the responses, I think this should be called something like 'forceometer' or 'gravitometer' and not accelerometer!
You get a -1 on the Z axis because gravity is acting on the device, applying a constant acceleration of 1G. I assume you want user acceleration, which you can get from the DeviceMotion object using a device motion handler as opposed to an acceleration handler. The userAcceleration property filters out the effects of gravity on the device and only gives you how much the user is accelerating it.
I found the answer [in the CoreMotion Reference guide, thanks to bensnider:
The accelerometer measures the sum of two acceleration vectors: gravity and user acceleration. User acceleration is the acceleration that the user imparts to the device.
You'll find the best answers in datasheet of the accelerometer used (LIS302DL).
It measures the gravity. The unit is chosen so that the gravity, 9.81 m/s^2, equals 1 unit. The sign tells how the phone axis is directed. In other words, what the phone considers downwards.
The phone measures 0 as acceleration in free fall. I don't know how much you want to throw your phone up and down to test it :)
When you're sitting, gravity is pulling you down to your chair. If it weren't for the chair or ground for that matter, you'd be falling down with acceleration of about 9.8m/s^2. In order for the chair to prevent you from falling down, it has to act with a force in the opposite direction with at least the same value.
The accelometer shows the value of the pulling force and it's a three-dimensional vector. In this case it's directed straight down. And the value given is expressed in G, units of gravity acceleration multiplied by that value.
Answerers keep missing the right wording that should set it straight for you... The device is "laying still" only relatively to you. It is actually not laying still at all. The http://en.wikipedia.org/wiki/Centripetal_force of gravity gives it (and you) centripetal acceleration. It is real, it is what keeps you from flying off Earth on a tangent, and it is what the accelerometer dutifully shows. (Earth is nothing special - we rotate about the Sun also etc etc, whose centripetal accelerations are way smaller, but they would be all shown by an accelerometer sensitive enough.)
I don't yet have sufficient reputation to reply directly to the comment by #gigahari above, but as an addendum, folks should be aware that some apps (such as the physics apps phyphox and PhysicsToolbox Sensor Suite) do not report (a+g) -- both phyphox's "with g" option and PhysicsToolbox report the vector sum (a-g), which is sometimes referred to as the "Operational Definition of Weight." A brief discussion of this version of the operational definition of weight is on WikiPedia, at https://en.wikipedia.org/wiki/Weight#Operational_definition

How do I measure the distance traveled by an iPhone using the accelerometer?

While GPS works for long distance changes, I would like to measure a shorter distance by using the iPhone's accelerometer.
Say I want to measure a height of a box using an iPhone application. You'd start the application, press a button to start measurement at the bottom of a box, move your iPhone from to the top of the box, then press a button to stop measurement. The application would then calculate and display the height of the box.
How would I use the accelerometer to perform this kind of measurement?
It is possible to do this, as I have implemented a more complex system on a sparkfun IMU.
There are a few components to do what you require accurately.
1) You need to filter the accellerometers signal using a low pass filter. This removes any noise that is not caused by your slow moving arm.
2) Integrate the 3 seperate acceleration values twice to go from acceleration to velocity, and then from velocity to distance.
3) The above method must be performed by keeing the phone in the same plane when you move it from the bottom of the box to the top. Any pitch/roll/yaw will disrupt the measurement(hint)
4) From above, to compensate for the pitch/roll/yaw, you can then include the built in gyro =]. Use this to map the vector obtained from the accellerometer to the starting point. Using this methodology you can measure the distance "through and object" by walking around it. (remember this gyro needs filtering too).
The final result depends on many factors such as, the effectiveness of your filter, the accuracy and sampling rates of your accellerometer and gyro, and the awsomeness of your mathematics and linnear algebra skills.
Try photographing an object of a known size at the distance of interest.
Depending on the application, and how much accuracy you need, you may be able to use the new 6-axis gyro accelerometers in the iPhone 4 and iPod Touch 4th Gen. You could get the total displacement by integrating the acceleration vector.
When integrating acceleration to get displacement, any errors will be cumulative, so this may not be appropriate, but may be worth considering.
GPS is currently not accurate enough to measure a box. Take into account that there may be an error of about 10 meters to a mile. You can get back the accuracy of the measure with CLLocation.
Pythagorean Theorem: c^2 = a^2 + b^2 (http://en.wikipedia.org/wiki/Pythagorean_theorem)
In your case, if point A = (Ax, Ay) and B = (Bx, By), then you can compute the distance C by:
C = sqrt( (Bx-Ax)^2 + (By-Ay)^2 )

Compensating compass lag with the gyroscope on iPhone 4

I've been experimenting with the compass and gyroscope on iPhone 4 and would like some help with an issue I'm having. I want to compensate for the slowness of the compass by using data from the gyroscope.
Using CMMotionManager and its CMDeviceMotion object (motionManager.deviceMotion), I get the CMAttitude object. Correct me if I'm wrong (please), but here is what I've deduced from the CMAttitude object's yaw property (I don't need pitch nor roll for my purposes):
yaw ranges from 0 to PI when the phone is pointing downwards (as indicated by deviceMotion.gravity.z) and swinging counterclockwise and 0 to -PI when swung clockwise
when the device is pointing upwards, yaw ranges from -PI to 0 and PI to 0, respectively
and from the compass data (I'm using locationManager.heading.magneticHeading), I see that the compass gives values from 0 to 360, with the value increasing when swinging clockwise
All right, so using all of this information together, I'm able to get a value I call horizontal that, regardless of whether the device is pointing up or down, will give values from 0 to 360 and increase when the device is swung clockwise (though I am still having trouble when deviceManager.gravity.z is around 0 -- the yaw value freaks out at this gravity.z value).
It seems to me that I could "synchronize" the horizontal and magneticHeading values, using a calculated horizontal value that maps to magneticHeading, and "synchronize" the horizontal value to magneticHeading when I feel the compass has "caught up."
So my questions:
Am I on the right track with this?
Am I using the gyro data from CMDeviceMotion properly and the assumptions I listed above correct?
Why might yaw freak out when gravity.z is around 0?
Thank you very much. I look forward to hearing your answers!
Just trying to answer... correct me if i'm wrong..
1.Yes you are on the right track
2.gravity in CM is already "isolated" from user gravity (gravity value caused by user acceleration) thats why there is two gravity, the "gravity" and "userAcceleration" its on apple CM documentation
// Note : not entirely isolated //
3.
if you have a gravity 0 it mean that the coresponding axis is perpendicular with gravity.
gravity.z is the iPhone screen thats why it -9.82m/s2 if you put on the desk with screen upright, actualy it hard to get 0 or maximum value of the gravity due to the sensor noise (it's normal, all sensor has a noise expecially cheap sensor).
what i do on my apps is I will switch my reference axis to other axis (in your case may be x or y) for certain limits, how the strategy is depend on the purpose or which side is your reference.
the other thing is, gyro is fast but its not stable, you need to re-calibrate the value for several interval. In my case every 5 second. I've experiment with gyro for calculating angle between two plane, i try with exacly 90 degree ruler and it will give an error about 0.5 degree every second try and keep increasing, but thats is mine, maybe others have a better method for avoid the error.
below is my steps "
Init
Read gravity XYZ -> Xg Yg Zg
Check if Xg < 0.25 If TRUE try Yg then Zg // Note 1 = 1g = 9.82 m/s^2
Read the compass and gyro
Configure and calibrate the gyro using the compass and calulate based on which axis i use in point 3.
If 5 second is pass then recalibrate, read the compass
If the the difference with gyro reading is > 5 degree skip recalibartion the gyro.
If the the difference with gyro reading is < 5 degree calibrate the gyro using compass value
Note: for number 7 : is to check if the phone affected with magnetic field or near huge steel such or high voltage electrical line or in noisy and heavy equipment in factory plant.
Thats all... Hope this could help you...
And sorry for my english..
Here is an example of an iPhone app where the compass get compensated with the gyroscope. Code and project can be seen here:
http://www.sundh.com/blog/2011/09/stabalize-compass-of-iphone-with-gyroscope/
The direction of the yaw axis vector is undefined when in zero gravity (or free fall, or close enough).
In order to do synchronization while in motion, you need to create a filter for your "horizontal" value that has the same lag/delay response characteristics as the magnetic compass. Either that, or wait until motion stops long enough for both values to settle before recalculating the offset.
Answer to question 1 is Yes, question 2 you are on the right track but you could use a variable name that is not 'horizontal', question 3 is answered by hotpaw2 and also a yaw in a chopper or helicopter at near zero altitude would alert the pilot with an alarm. There is a time lag because part of the software is local while there are other factors which can slow it down including access to a sensor for detecting magnetic waves, the device position and direction, preparing the graphic output for the compass display, computing and outputting data from the gyro and sensors through a relatively slow interface, using a general purpose handheld device not custom designed for the type of task being asked of it.