1

I know i am opening up a can of worms with trying to get the linear motion of a device using the accelerometer, but please just humor me.

I am trying to figure out the right formula to take the Sensor.TYPE_LINEAR_ACCELEROMETER (which i believe is normal accelerometer data minus gravity) and essentially say "this much time has passed and the i have accelerated x amount since last time, so i have traveled d amount.

should be something like distanceTraveledOnX = linearAccerationOfX * TimePassed;

easy enough in the real world right? if i have been going 1 mile a minute for 10minutes then i have traveled 10 miles.. speed * time = distance

problem is im not sure what the linearAcceleration is using for unit of measure. I know my timePassed is in NanoSeconds as i am saying (in my onSensorChanged)

currentTime = System.nanoTime();//var of type (double) timePassed = currentTime - lastTime; lastTime = currentTime;

can someone please help me figure out the formula for translating the linearAcceleration value to a nanoSecond measurement..

thanks

EDIT

here is the code im currently using but im always getting 0 :

public void onSensorChanged(SensorEvent evt) {   
 if (type == Sensor.TYPE_LINEAR_ACCELERATION) {

                        newTime = System.currentTimeMillis()/1000;
                        float oldVelocity = lastTime1-lastTime0;
                        float newVelocity = newTime- lastTime1;
                       if(oldVelocity<1)oldVelocity =1;

                        newX = lastX1 + ((lastX1 - lastX0)/oldVelocity)*newVelocity +(evt.values[0]/2)*(newVelocity*newVelocity);
                        lastX0 = lastX1;
                        lastX1 = newX;
                        lastTime0 = lastTime1;
                        lastTime1 = newTime;

                        Log.v("SENSOR MAN LINEAR", "new X:"+newX);


                    }
}
erik
  • 4,946
  • 13
  • 70
  • 120
  • Except that post doesn't answer it either – erik May 24 '13 at 20:39
  • No, they explain that due to rapid integration of inevitable error, it's not a solvable problem - not really even with sensors costing orders of magnitude more than those in a phone. – Chris Stratton May 24 '13 at 21:22
  • but, for my purposes (just measuring a couple feet difference) i think it is.. – erik May 24 '13 at 21:29
  • No, it's not. You can't tell the difference between a device which is sitting still and one which is moving smoothly, nor can you determine the start and stop and direction of change in movement with sufficient accuracy to tell how fast you are moving. With a double integral, tiny errors rapidly blow up. – Chris Stratton May 24 '13 at 21:30
  • Ok sure.. but i can look at a linear graph of lets say the LinearAcceleration of the x axis.. Its sitting at 0 for a while and then i see the graph swing up (lets say 20 points) and swing down about -10 units and back up to 0 where it again hovers for a bit.. i can tell that the user probably just moved the device up on that axis about 10 units.. at least that would be my human translation. – erik May 24 '13 at 21:42
  • 1
    Well, good luck. Take some data and try to translate your human sense to code without the errors blowing up on you (and don't forget that the phone can be rotated, shaken, etc as it moves). If you can get useful results from a phone-grade sensor you may have a promising career in rocket science. But it really takes no more than armchair examples to realize why such sensors find some use for measuring *changes* of movement, but not distances. – Chris Stratton May 24 '13 at 22:45
  • Erik wants to know how one would do the calculation, he does not care if it's correct or not, and the question is not about how usable the result is. – Mars May 14 '15 at 19:46
  • I found an even better answer to this question: http://stackoverflow.com/a/7835988/338479 – Edward Falk Jun 14 '16 at 15:43

2 Answers2

1

This stuff is high school physics, and if you don't know the difference between acceleration and velocity, you'll need to review it before you have any hope here.

I can tell you this much: the linear acceleration readings from a cell phone or tablet aren't remotely precise or accurate enough to do what you want without constant correction (via gps or other methods). There is an entire field of study trying to solve this problem. I've attended conferences on it.

That said, you also need to take into account that the orientation of your device will also change, unless this is some sort of special application, e.g. the device is trapped onto a sled which can only move in one direction.

Let's assume that case, and assume that the device is strapped to your sled with the right side of the device (+X axis) aligned in the direction of travel. Let's also assume that the initial position of the sled is known (call it X0) when the program starts, and that the initial velocity is zero.

Your code looks approximately like this:

double x0;    // previous position, meters
double x;     // current position
double v0;    // previous velocity, meters/second
double v;     // current velocity
long t0;      // previous time, nanoseconds
long t;       // current time

public void onStart() {
    x0 = getInitialPosition();
    x = x0;
    v0 = 0;
    v = v;
    t0 = System.getCurrentTime() * 1000000;
    // Enable sensors; left as an exercise for the reader
}

public void onSensorChanged(SensorEvent event) {
    // Assume linear acceleration is the only active sensor
    double accel = event.values[0];   // X axis is our axis of acceleration
    t = event.timestamp;
    double dt = (t - t0) * .000001;
    v = v0 + accel * dt;
    x = x0 + v * dt;
    t0 = t;
    v0 = v;
    x0 = x;
}

This is by no means a complete solution. Doing this right involves differential equations which I'm not equipped to explain here (translation: I've forgotten everything I learned in college). However, if your acceleration value is accurate enough, and your time slice is short enough, this is viable.

If you need to solve this in more than one direction, it's only slightly more complicated provided that the device never changes orientation. If it does, then you also need to capture the rotation sensor and learn about quaternions and rotation matrices.

And even if you do everything right, errors will still accumulate, so now you want some sort of correction factor based on GPS, known geometry of the environment (e.g. if you're indoors and the software has a map of the building, it can make corrections when you turn a corner), and other environmental clues such as WiFi hotspots in known locations.

You might want to read up on Kalman filters at this point.

Executive summary: this is a HARD problem in the general case, and if you solve it, there's probably fame and fortune waiting for you.

Edward Falk
  • 9,991
  • 11
  • 77
  • 112
  • and while my code always gives me 0 for the new X yours always gives something like -1 and 3.. essentially we are both wrong! – erik May 24 '13 at 19:30
  • Adding on: I just found a superb video that explains why this is hard: https://www.youtube.com/watch?v=C7JQ7Rpwn2k#t=23m22s – Edward Falk Jun 14 '16 at 15:39
0

Well, the correct form, known from school, is finalXPosition = (linearAcceleration*timePassed^2)/2+ initialVelocity*timePassed+initialXPosition

finalVelocity = initialVelocity*timePassed

chaining these chunks you'll get your theoretical values.

In practice, best results are achieved by regular calibration of initialXPosition and initialVelocity through GPS.

simple example to receive calibrated horizontal acceleration in onSensorChanged:

class Integrator {
    private float position = 0f;
    private float velocity = 0f;

    public void setGpsPosition (float gpsPosition) {
        position = gpsPosition;
    }
    public void setGpsVelocity (float gpsVelocity) {
        velocity = gpsVelocity;
    }
    public void onAccelerationChangeHandler(float acceleration, float timePassed) {
        position += acceleration*timePassed*timePassed/2f + velocity*timePassed;
        velocity += acceleration*timePassed;
    }
    public float getCurrentPosition() {
        return position;
    }
}

usage for x-acceleration:

long lastTime = 0;
public void onSensorChanged(SensorEvent evt) { 
    if (evt.sensor.getType() == Sensor.TYPE_LINEAR_ACCELERATION) {
        long newTime = System.currentTimeMillis();
        OnAccelerationChangeHandler(evt.values[0], (newTime-lastTime)/1000);
        lastTime = newTime;
    }

Please, note that outside a minute scale the error makes this all meaningless w/o gps correction. Understand, that if you are walking at constant speed the sensor won't give you anything at all.

alexei burmistrov
  • 1,417
  • 10
  • 13
  • whats the difference between initialVelocity and linearAcceleration – erik May 23 '13 at 20:49
  • Velocity is how fast your position changes.acceleration is how fast your velocity changes. Thus, moving with constant velocity is undetectable by your accelerometer – alexei burmistrov May 24 '13 at 05:03
  • i guess im still not understanding what FINAL velocity is used for.. also do i get velocity by saying "new linearAcceleration - last linearAcceleration – erik May 24 '13 at 12:18
  • 1. Usage: next time, in onSensorChanged you will set initialXPosition to old finalXPosition and initialVelocity to old finalVelocity. 2. No, on the contrary, linearAcceleration = (finalVelocity - initialVelocity) / timePassed. It seems, that you don't get what acceleration is: if you are a driver, maximum velocity of your car is, e.g. 200 km/h, but maximum acceleration is how fast you car gets from standing still (0 km/h) to, say, 100 km/h and is measured in [km/h per second]. – alexei burmistrov May 24 '13 at 14:30
  • forgive me im really not getting it.. can you please show me exactly what variables you are setting up initially and how you would manipulate them in the onSensorChange in your answer.. pretty please? – erik May 24 '13 at 16:14
  • when i try to follow what you are saying, no where are you actually referencing the data from the sensor – erik May 24 '13 at 16:26
  • Do you mean something like that? See the answer – alexei burmistrov May 24 '13 at 17:49
  • that always gives me 0 for position – erik May 24 '13 at 18:37
  • i have now included the code im trying to use and also always getting zero for new X – erik May 24 '13 at 18:41
  • as you can see you have middle part of your newX calc incorrect – alexei burmistrov May 24 '13 at 20:09