Question

Short question: acceleration from CoreMotion values get rather large drift even device laying on table. Is it ok or what am I doing wrong?

Long question: I am using CoreMotion accelerometer like that, in -init method:

motionManager = [[CMMotionManager alloc] init];
motionManager.deviceMotionUpdateInterval = 1.0 / 60.0;

then start updating it:

if ([motionManager isDeviceMotionAvailable])
{
    [motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXArbitraryCorrectedZVertical];
}

and then read values in some update method (invoked by Cocos3d by timer). Also, I've got a static variable accum - accumulator, which add current values of acceleration to it. So accum holds a sum of all acceleration values:

if (motionManager.deviceMotionActive)
{
    CMDeviceMotion *deviceMotion = motionManager.deviceMotion;
    CMAcceleration accel = deviceMotion.userAcceleration;
    static CC3Vector accum = {0,0,0};
    accum.x += accel.x;
    accum.y += accel.y;
    accum.z += accel.z;
    NSLog(@"%f, %f, %f", accum.x, accum.y, accum.z);
}

I lay my iPad 3 on table and acceleration values seemed to be ok by first glance, but it becomes visible that value in accum in one axis start to increase pretty quickly. I know, that removing gravity force from raw data is not 100% accurate, but I did not expected that this is so bad even with iPad laying on table and not moving. So the question is am I doing something wrong or this is how it should be?

Was it helpful?

Solution

The accelerometer is far too noisy to accurately integrate velocity, even if you know the direction and strength of gravity precisely.

You might be able to neutralise bias somewhat by accumulating an average acceleration vector and subtracting that, but obviously that will cease to work the instant you tilt or accelerate the device.

OTHER TIPS

One way to help get greater accuracy would be to use something like this:

accum.x += (previous_accel.x - accel.x)/2;
previouis_accel.x = accel.x;

You automatically lose data when you take and record raw sensor readings like you see in the ugly picture / graph I made below. By averaging the last reading and the current reading you can help smooth out (or fill in) the missing info.
Data "lost" between samples

You probably recognize this from calculus 1 (least squares method I think), anyway just like in calculus the smaller the intervals the closer you get to the real info. I guess I am asking, are you sampling at max frequency?

The other (kind of) basic data management technique that is always recommended when using an accelerometer is a low-pass filter. It is easy enough to implement and even with out the averaging technique above it will eliminate your drift when stationary. If you haven't heard of one, it is just a test of the values read to see if they are large enough to be anything other than noise. (Noise can be caused by many things but from what I have read temperature is one of the biggest problems followed by micro vibrations we mortals cannot detect).

if(accel.x < .05)
    accel.x = 0.0;

The actual value used will totally depend on your sensor and, to some degree, what you are trying to do / how sensitive the readings need to be so you need to do some testing to figure out the best value for your situation. I would output to a csv file if I could and import them into a spreadsheet with graphing capability. It can be extremely helpful to see the data in a graph both for the filter testing and later on when debugging your program.

You're using CMAttitudeReferenceFrameXArbitraryCorrectedZVertical, which updates the yaw based on the magnetometer. While this usually does a good job of correcting long-term values it does tend to drift depending on the environment.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top