Android线性加速,计算轨迹

时间:2016-02-15 14:34:09

标签: java android accelerometer physics

我想在我的汽车中使用加速度计并使用加速度计值,在excel或任何其他平台上绘制轨迹,原点位于第一个位置值,即路径的开头。

我怎样才能做到这一点?请告诉我细节,我没有任何物理概念。

请提前帮助,谢谢。

PS:我已经编程了SensorListener ......

我有这个例子:

@Override
public void onSensorChanged(SensorEvent event){
    if(last_values != null){
        float dt = (event.timestamp - last_timestamp) * NS2S;
        for(int index = 0 ; index < 3 ; ++index){
            acceleration[index] = event.values[index];
            velocity[index] += (acceleration[index] + last_values[index])/2 * dt;
            position[index] += velocity[index] * dt;
        }
        vxarr.add(velocity[0]);
        vyarr.add(velocity[1]);
        vzarr.add(velocity[2]);
        axarr.add(acceleration[0]);
        ayarr.add(acceleration[1]);
        azarr.add(acceleration[2]);
    }
    else{
        last_values = new float[3];
        acceleration = new float[3];
        velocity = new float[3];
        position = new float[3];
        velocity[0] = velocity[1] = velocity[2] = 0f;
        position[0] = position[1] = position[2] = 0f;
    }
    xarr.add(position[0]);
    yarr.add(position[1]);
    zarr.add(position[2]);
    tvX.setText(String.valueOf(acceleration[0]));
    tvY.setText(String.valueOf(acceleration[1]));
    tvZ.setText(String.valueOf(acceleration[2]));
    last_timestamp = event.timestamp;
}

但是当我用手机画圆圈时,我得到了这个:

enter image description here

有时候我只有负值,有时候我只有正值,为了得到圆,我从来没有负的正值。

2 个答案:

答案 0 :(得分:1)

加速度是时间速度的衍生物(换言之,速度变化率);速度是时间位置的导数。因此,加速度是位置的二阶导数。相反,位置是加速度的第二个反向衍生物。您可以采用加速度计测量并随着时间的推移进行双重积分以获得轨迹的位置,除了两个问题:

1)它是一个不定的积分,即有无限多的解(见例如https://en.wikipedia.org/wiki/Antiderivative)。在这种情况下,这意味着您的测量结果不会告诉您初始速度。但是你可以从GPS(精度有限)或某种形式的用户输入中获得它(例如,当用户按某个按钮开始计算轨迹时,假设速度为零)。

2)错误累积。假设任何给定方向上的加速度计误差a = 0.01 m / s ^ 2(基于我的手机的粗略猜测)。超过t = 5分钟,这会给你一个* t ^ 2/2 = 450米的误差。

因此,您无法获得非常准确的轨迹,尤其是在很长一段时间内。如果这对您无关紧要,您可以使用其他答案中的代码,或编写自己的代码等,但首先您需要了解此方法的非常严重的局限性。

答案 1 :(得分:0)

如何使用加速度计值计算设备的位置?

物理学家喜欢将给定时间的物体在空间中的位置视为具有值(x(t),y(t),z(t))的数学函数p(t)。该物体的速度v(t)证明是p(t)的一阶导数,加速度a(t)很好地拟合为v(t)的一阶导数。

从现在开始,我们只看一个维度,另外两个可以用同样的方式处理。

为了从加速度中获得速度,我们必须使用我们已知的初始值“反转”操作(没有它们我们不会获得唯一的解决方案)。

我们面临的另一个问题是我们没有加速功能。我们只是通过加速计传感器或多或少地将样本值传递给我们。

因此,在向爱因斯坦,牛顿和黎曼祈祷时,我们采用这些值并将加速函数视为粘合在一起的许多小线。如果传感器经常发射,这将是一个非常好的近似值。

现在我们的问题变得更加简单:线性函数的(不定)积分(=反导数) f(t) = m*t + bF(t) = m/2 * t^2 + b*t + c,其中c可以选择满足初始条件(在我们的情况下为零速度)。

让我们使用点斜率形式来模拟我们的近似值(时间值t0和t1以及相应的加速度值a0和a1):

a(t) = a0 + (a1 – a0)/(t1 – t0) * (t – t0)

然后我们得到(首先计算v(t0) + "integral-between-t0-and-t-of-a",然后使用t1代替t

v(t1) = v(t0) + (a1 + a0) * (t1 – t0) / 2

使用相同的逻辑,我们还得到了一个位置公式:

p(t1) = p(t0) + (v(t1) + v(t0)) * (t1 – t0) / 2

转换为代码,其中last_values用于存储旧的加速度值:

float dt = (event.timestamp - last_timestamp) * NS2S;
for(int index = 0 ; index < 3 ; ++index){
    acceleration[index] = event.values[index];
    float last_velocity = velocity[index];
    velocity[index] += (acceleration[index] + last_values[index])/2 * dt;
    position[index] += (velocity[index] + last_velocity )/2 * dt;

    last_values[index] = acceleration[index];
}

**编辑:**

只要我们的设备与世界的坐标系统对齐,所有这一切对我们都有用。几乎不会是这种情况。所以之前计算我们的值之前,我们首先必须使用类似SensorManager.getRotationMatrix()的旋转矩阵将它们转换为世界坐标。

Csaba Szugyiczki在此answer中有一段代码片段,其中显示了如何获取旋转矩阵。

但是getRotationMatrix()上的documentation说明了

  

如果设备正在加速或置于强磁场中,则返回的矩阵可能不准确。

...所以我在驾驶汽车时使用它有点悲观。