Android线性加速度,计算轨迹
Posted
技术标签:
【中文标题】Android线性加速度,计算轨迹【英文标题】:Android Linear Acceleration, calculating a trajectory 【发布时间】:2016-02-15 14:34:09 【问题描述】:我想在我的车上使用我的加速度计,并使用加速度计值,在 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;
但是当我用手机画一个圆圈时,我得到了这个:
有时我只有负值,有时我只有正值,我从没有负值和正值来获得圆圈。
【问题讨论】:
我不确定我是否理解您的代码和图像之间的关系,但无论如何:也许这个link 会有所帮助。 我只是在 X 轴上绘制 xarr,在 Y 轴上绘制 yarr,因为 xarr 和 yarr 应该给我手机所遵循的路径,而显然不是 链接没有用,我读了上千遍来制作我的 SensorListener 很抱歉。对我来说,一件新鲜事当然是,一个正在躺着的设备仍然有一个积极的加速。需要习惯,但从更普遍的角度来看是有道理的;)好的,我会调查问题并在发现问题后立即回来。 看起来您从未更新 last_values。可能应该是该轴上的最后一个加速度值? 【参考方案1】:加速度是速度对时间的导数(换句话说,速度的变化率);速度是位置对时间的导数。因此,加速度是位置的二阶导数。相反,位置是加速度的第二个反导数。您可以进行加速度计测量并随着时间的推移进行双重积分以获得轨迹的位置,除了两个问题:
1) 它是一个不定积分,即有无限多个解(参见例如https://en.wikipedia.org/wiki/Antiderivative)。在这种情况下,这意味着您的测量结果不会告诉您初始速度。但是您可以从 GPS(精度有限)或某种形式的用户输入(例如,假设当用户按下某个按钮开始计算轨迹时速度为零)获取它。
2) 错误累积。假设任何给定方向的加速度计误差 a = 0.01 m/s^2(基于我的手机的粗略猜测)。在 t = 5 分钟内,这会给您带来 a*t^2/2 = 450 米的误差。
因此,您无法获得非常准确的轨迹,尤其是在很长一段时间内。如果这对您来说无关紧要,您也许可以使用其他答案中的代码,或者编写自己的代码等,但首先您需要意识到这种方法的非常严重的局限性。
【讨论】:
如果给出了初始条件(即位置和速度的值),则微分方程的解存在并且是唯一的。话虽如此,我绝对同意你的观点,即在“现实生活”条件下结果不会很准确,因此最好使用 GPS。 我特别提到了初始条件。 是的,你做到了。并且您建议了一种如何获取初始值的方法。我没有错过,但不知何故,我认为很多人可能会。因为我知道要寻找什么。现在其他人可能会在“无限多的解决方案(见......”加上一些指向数学主题的链接之后很快停止关注。所以我只是想澄清一下,很抱歉它可能被解读为与您所写的内容相矛盾。并且我再说一遍,你对这个问题的贡献非常有用。我确信代码存在一些可以修复的问题。但正如你所说:这种方法本身有严重的局限性。 例如,OP 评估所有 event.values 而不检查事件类型。但是由于 OP 似乎已经失去了兴趣,我想知道是将其包含在我的帖子中还是完全删除我的帖子。其中一半不是关于编程,而是关于数学。一个有趣的谜题,但可能跑题了。 不要删除它,有人会发现它作为编程示例很有用。旋转矩阵方法的使用也很有趣——我没有意识到这一点,因为我实际上还没有机会处理 android 编程的这一面。顺便说一句,可以仅根据理想的加速度计测量值来计算轨迹平面的基础,除非还有一个未知的初始值(方向)。【参考方案2】:如何使用加速度计值计算设备的位置?
物理学家喜欢将物体在给定时间的空间位置视为具有值( x(t)、y(t)、z(t) )的数学函数 p(t)。该物体的速度 v(t) 是 p(t) 的一阶导数,而加速度 a(t) 很好地拟合为 v(t) 的一阶导数。
从现在开始,我们只看一个维度,其他两个可以同样处理。
为了从加速度中获得速度,我们必须使用我们已知的初始值“反转”操作(没有它们,我们将无法获得唯一解)。
我们面临的另一个问题是我们没有将加速度作为函数。我们只是通过加速度传感器或多或少地频繁地传递给我们的样本值。
因此,向爱因斯坦、牛顿和黎曼祈祷,我们采用这些值并将加速函数视为许多粘合在一起的小线。如果传感器经常触发,这将是一个非常好的近似值。
我们的问题现在变得简单多了:线性函数的(不定)积分(= 反导数)
f(t) = m*t + b
是F(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 中有一个代码 sn-p,它显示了如何获取旋转矩阵。
但正如getRotationMatrix()
上的documentation 所述
如果设备正在加速或置于强磁场中,返回的矩阵可能不准确。
...所以我对开车时使用它有点悲观。
【讨论】:
@Roman Panaget - 很抱歉,我在写这个答案时发现我的计算结果(来自聊天)有一个错误。请注意,您用于速度的公式是正确的(当计算变得有点混乱时,我忽略了 v(to) + ...),但位置的公式确实应该类似于另一个。以上是关于Android线性加速度,计算轨迹的主要内容,如果未能解决你的问题,请参考以下文章