如何根据手机加速度计算距离

发布于 2024-10-05 15:56:52 字数 527 浏览 0 评论 0原文

我想构建类似的东西,但使用 Android 手机: http://www.youtube.com/ watch?v=WOt9mb5QqRs

我已经构建了一个通过套接字发送传感器信息的应用程序(仍在寻找适用于 Android 的良好 websocket 实现)。我打算使用该信息与网络应用程序进行交互,例如我可以根据手机的移动来移动图像。 问题是我尝试根据加速度计数据计算距离,但结果非常糟糕。我想知道是否有人可以帮助我找到正确的方程,但首先,是否可以做到这一点?

到目前为止,我使用以下方程:

速度 = 加速度 * 时间;

距离 = 速度 * 时间 + (加速度 * 时间^2) / 2;

然后我翻译距离从米每秒到基于显示器屏幕分辨率的像素。

每次我收到传感器数据(每约 80 毫秒)时,都会在浏览器中使用 JavaScript 进行计算。

I want to build something like this but using an android phone: http://www.youtube.com/watch?v=WOt9mb5QqRs

I've already built an app that sends sensor information via socket (still looking for a good websocket implementation for android). I intend to use that information to interact with a web app, so for example i would be able to move an image based on the phone movement.
The problem is that I tried to calculate distance based on the accelerometer data but the results are really bad. I wonder if anyone could help me with the correct equation, but first of all, is it possible to do this?

Till now I'm using the following equations:

velocity = acceleration * time;

distance = velocity * time + (acceleration * time^2) / 2;

then I translate distance from meters per second to pixels based on monitor screen resolution.

that's calculated with javascript in the browser every time i receive sensor data, which is every ~80ms.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

怎言笑 2024-10-12 15:56:52

基础知识很简单。在模拟世界中,您使用连续数学:

velocity = integrate(acceleration)
distance = integrate(velocity)

而在数字世界中,则更容易,您使用离散数学,其中积分变成求和:

velocity = sum(acceleration)
distance = sum(velocity)

只需将您读取的所有加速度值不断相加,最终就可以得到距离。

最大的问题是,在地球上,由于重力,存在大约 10m/s/s 的恒定向下加速度。找出矢量的哪一部分是重力是困难的部分。

顺便说一句,重力是加速度计检测倾斜的方式。因此,无论你怎么做,除非你可以独立于加速度计计算倾斜(例如在陀螺仪的帮助下),否则你的代码将主要测量倾斜而不是距离。


哈!我刚刚从我的上一个声明中意识到很多 iPhone 应用程序无法在太空中运行:-P


附加答案:

根据 OP 发布的“评论”(作为此答案下方或上方的答案),看起来我需要提供进一步的解释。实现非常非常简单,不熟悉数学的人会认为它一定比这更复杂。伪代码如下:

// Set distance to zero at start-up:
var distance_X = 0
var velocity_X = 0

function update_acceleration_X (acceleration_X) {
    velocity_X = velocity_X + acceleration_X
    distance_X = distance_X + velocity_X
}

// To use the distance value just read the distance_X variable:
function get_distance_X_and_reset () {
    x = distance_X
    distance_X = 0
    return x
}

距离始终从软件首次启动的位置开始测量,除非将距离变量重置为零。必须不断读取加速度计(最好以加速度计本身测量力的速率)并相应更新速度和距离值。当您想知道距起点的距离时,只需读取距离变量即可。

有几点:任何程度的倾斜,无论多么轻微,都会增加漂移。这意味着除非不断跟踪倾斜角度本身,否则在一个方向或另一个方向上总会有少量的恒定加速度。即使是配备高精度加速度计和陀螺仪的核潜艇,因为 GPS 无法在水下工作,也需要定期浮出水面并与 GPS 同步以纠正这种漂移。

其次,加速度计测量的是力,而不是运动。任何类型的力都会被测量。我提到了重力,但它也测量了与桌子摩擦引起的颠簸、心跳和呼吸导致的手轻微颤抖时的脉搏等等。好消息是,从长远来看,所有这些力量都会趋于平均,并且公式仍然是正确的。但从短期来看,这意味着你的阅读会很吵。人们想出了很多技巧来使用韦纳滤波器和卡尔曼滤波器等来最大限度地减少这种噪音。

第三,您可能已经注意到,加速度计读数并不是恒定的。我的意思不仅仅是每次读取时的值都不同,这是显而易见的,而且它也会在两次读取之间改变值。我们错过的每个值都会影响我们的准确性,因此尽可能频繁地读取这些值非常重要。现在,好消息是,从长远来看,由缺失值引起的所有这些误差应该会平均,因为它们主要是由不平稳的运动或振动引起的,并且我们的公式仍然是正确的。但这再次意味着,从短期来看,这会给我们的系统增加噪音。如果您使用卡尔曼滤波器等良好的预测滤波器,那么它应该能够解决这个问题,但较弱的滤波器可能需要一些帮助。一种方法是将每个加速度读数与前一个读数进行平均。请注意,它必须是先前的“真实”读数,而不是先前的平均读数。

比这更精确的领域是惯性测量单元 (IMU) 和惯性制导以及大量相当复杂的矢量和矩阵数学。不过,有一些开源项目在做这件事(不到 10 年前,这些东西完全是军事用途,因为你知道,潜艇和巡航导弹都使用它们)。

这些 Sparkfun 文章的底部有一些不错的链接和一些参考代码:

http://www.sparkfun.com/ products/9268

http://www.sparkfun.com/products/8454

希望所有这些都有帮助。如果其他人有任何可能有帮助的文章的链接,请发表评论。


示例

当然,如果您想要真实单位,则需要缩放采样率。例如,以 9m/s/s 加速 80ms 意味着您的速度为 (9m/s/s * 0.08s) = 0.72m/s。假设您不关心单位,上面的伪代码将被简化。最终值仍将距离表示为数字,只是该数字与任何现实世界的测量单位几乎没有关系。您可以简单地在最后应用缩放函数来校准您的像素值。无论如何,这里有一个使用现实世界单位的示例来阐明正在发生的情况:

given the following acceleration readings:
9m/s/s
3m/s/s
0m/s/s
0m/s/s
0m/s/s
-5m/s/s
-7m/s/s

assuming an 80ms sample rate
we can derive the following velocities:
0.72m/s (what you get from accelerating 9m/s for 80ms)
0.96m/s
0.96m/s
0.96m/s
0.96m/s
0.56m/s
0m/s

from that we can derive the following distances:
57.6mm (what you get from moving at 0.72m/s for 80ms)
134.4mm
211.2mm
288mm
364.8mm
409.6mm

现在,如果您采用导出的距离并按照通常的方式进行反向计算(v = (s2-s1)/t 和 < code>a = (v2-v1)/t) 你应该得到加速度读数。

The basics is simple. In the analog world you use continuous math which is:

velocity = integrate(acceleration)
distance = integrate(velocity)

and in the digital world it is even easier, you use discrete math where integration becomes summation:

velocity = sum(acceleration)
distance = sum(velocity)

Just keep adding up all the values of acceleration you read and you eventually get distance.

The big problem with this is that on planet Earth there is a constant acceleration downwards of approximately 10m/s/s due to gravity. Figuring out which part of your vector is gravity is the hard part.

BTW, gravity is how accelerometers can detect tilt. So however you do it, unless you can calculate the tilt independently of the accelerometers (for example with the help of gyros) your code will mostly be measuring tilt instead of distance.


HA! I just realized from my last statement that a lot of iPhone apps won't work in space :-P


Additional answer:

Based on a "comment" posted by the OP (as an answer either below or above this answer) it looks like I need to provide further explanation. The implementation is really-really simple that people not familiar with the maths will think it must be more complicated than that. The pseudocode is as follows:

// Set distance to zero at start-up:
var distance_X = 0
var velocity_X = 0

function update_acceleration_X (acceleration_X) {
    velocity_X = velocity_X + acceleration_X
    distance_X = distance_X + velocity_X
}

// To use the distance value just read the distance_X variable:
function get_distance_X_and_reset () {
    x = distance_X
    distance_X = 0
    return x
}

Distance is always measured from where the software first starts unless you reset the distance variable to zero. The accelerometer must constantly be read (preferably at the rate the accelerometer itself measures forces) and the values of velocity and distance updated accordingly. When you want to know the distance from the starting point just read the distance variable.

Several things: any amount of tilt, no matter how slight, will add drift. Meaning that there will always be a small amount of constant acceleration in one direction or the other unless the angle of tilt itself is constantly tracked. Even nuclear submarines, equipped with high precision accelerometers and gyros because GPS doesn't work under water, need to periodically surface and sync with GPS to correct this drift.

Second, the accelerometer measures force, not movement. Any kind of force is measured. I mentioned gravity but it also measures bumps caused by friction with a table, your pulse as your heartbeat and breathing cause your hand to shake slightly, anything. The good news is that over the long run all these forces will average out and the formula will still be correct. But in the short run it means your reading is going to be noisy. There are a lot of tricks people have come up with to minimize this noise using things like Weiner and Kalman filters.

Third, as you may have noticed, the accelerometer reading is not constant. I don't simply mean that the values are different each time you read them, that is obvious, but it also changes values in-between readings. Every value we miss affects our accuracy so it is important to read the values as often as possible. Now, the good news is that in the long run all these errors caused by missing values should average out as they are mostly caused by jerky movements or vibrations and our formula is again still correct. But it means again that in the short run this adds noise to our system. If you use a good perdictive filter like a Kalman filter then it should be able to account for this but weaker filters may need some help. One way of doing this is to average out each acceleration reading with the previous reading. Note that it must be the previous "real" reading, not the previous averaged reading.

More accuracy than this goes into the realm of Inertial Measurement Units (IMU) and inertial guidance and a lot of fairly hairy vector and matrix maths. There are open source projects doing this though (less than 10 years ago this stuff was strictly military since, you know, submarines and cruise missiles use them).

These Sparkfun articles have some nice links at the bottom and some reference code:

http://www.sparkfun.com/products/9268

http://www.sparkfun.com/products/8454

Hope all this helps. And if anyone else have links to any article which may help please comment.


Example

Of course if you want real units you need to scale for sample rate. For example accelerating at 9m/s/s for 80ms means your velocity is (9m/s/s * 0.08s) = 0.72m/s. The above pseudocode is simplified assuming you don't care about units. The final values will still represent distance as a number it's just that the number has little relation to any real world unit of measurement. You can simply apply a scaling function at the end calibrated to your pixel valus. Anyway, here's an example with real-world units to clarify what's happening:

given the following acceleration readings:
9m/s/s
3m/s/s
0m/s/s
0m/s/s
0m/s/s
-5m/s/s
-7m/s/s

assuming an 80ms sample rate
we can derive the following velocities:
0.72m/s (what you get from accelerating 9m/s for 80ms)
0.96m/s
0.96m/s
0.96m/s
0.96m/s
0.56m/s
0m/s

from that we can derive the following distances:
57.6mm (what you get from moving at 0.72m/s for 80ms)
134.4mm
211.2mm
288mm
364.8mm
409.6mm

Now, if you take the derived distances and do a reverse calculation as per usual (v = (s2-s1)/t and a = (v2-v1)/t) you should get the acceleration readings back.

李白 2024-10-12 15:56:52

最大速度 = 时间 * 加速度。
平均速度 = 最大速度 / 2。
行驶距离 = 平均速度 * 时间。


行驶距离=时间*时间*加速度/2。

Max velocity = time * acceleration.
Average velocity = Max velocity / 2.
Distance travelled = Average velocity * time.


Distance travelled = time * time * acceleration / 2.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文