I'm experimenting with sensors in Android and decided to make an app to measure the distance by which the device moves, using the linear acceleration sensor. I came up with a following piece of code:
override fun onSensorChanged(e: SensorEvent?) {
if (e != null) {
when (e.sensor.type) {
Sensor.TYPE_LINEAR_ACCELERATION -> {
var time = if (dta != 0L) (e.timestamp - dta) * 10f.pow(-9) else 0f
for (i in 0..2) {
acceleration[i] = e.values[i]
position[i] += acceleration[i] * time * time / 2
}
dta = e.timestamp
}
}
}
}
where dta
is the time of the last sensor update and acceleration
and position
are mutable state lists, displayed in the activity.
However, I noticed that the measurements are very inaccurate. To reduce error, I decided to set acceleration[i]
to 0f
if the corresponding event value is below a threshold. But still, even if the reading seem correct, I don't have a good way to at least partially accurately convert raw acceleration data to position changes.
I don't really know how to cope with that, for example because of the acceleration characteristic of the human steps (they keep once increasing once decreasing), as shown on the graph plotted in the activity:
Where red means X acceleration, green - Y, blue - Z and black is the "total" acceleration - the square root of the sum of squared single-axis accelerations.
What I find noteworthy is that the idea of the app is to measure the distance traveled in the range of 1 to 5 meters, at the rate of a person's normal walking pace (he presses a button, walks over, puts the phone down and goes back to the original location), so the period of movement should not be longer than a minute. Given such orders of magnitude, sensor drift shouldn't mess that much, but at cost of no possibility to use GPS to correct the results.
I'd like to achieve accuracy of 15-20 centimeters. Is this possible, and if so, how to achieve such effect? And if not, are there any other ways to effectively measure the user's distance from the device? I've heard of Google ARCore that should be theoretically able to calculate distance between two points (called Hit Records) but the quality of the readings heavily depend on the camera quality and lighting conditions. I've also read (here,
here,
here,
here and
here) advice about "implementing Kalman filters" and "fusing sensors" - what does it mean? Maybe it could help?
I truly apprectiate every answer!
You don't. There's a lot of problems with accelerometers that make them inappropriate for measuring distance.
1)Even if they worked perfectly, the double integration (from acceleration->speed->distance) would cause the natural noise in the sensor to be magnified immensely.
2)Accelerometers by their nature are noisy. They need to be HEAVILY filtered to get decent results for something like this. Unless you're an expert in DSP, you're unlikely to do it well.
3)Accelerometers are not designed for this. They max out- there is a maximum acceleration they can measure, and beyond that they can't increase. What this is depends on the exact model of sensor, but you can easily hit that point by jogging.
4)Accelerometers measure acceleration. Not speed. So if you travel at a constant 1m/s, the accelerometer would always measure 0 (ignoring noise). Thus you'd see 0 movement, even though you're moving at 1m/s. In other words, when you integrate acceleration into velocity and get v= v_0+a(t)*t
, the v_0 term is not measurable by an accelerometer. When you integrate again to distance x(t)= x_0+v_0*t+1/2a(t)^2
, the x_0 and v_0 terms are both zeroed out, a significant error.
5)Tilt/rotation. Hold your phone out while sitting still and rotate your wrist quickly. YOu'll see an acceleration spike from the centrifical force of the rotation. But you didn't move. You could maybe cancel this out by reading the gyroscope and doing some math, but gyroscopes are also noisy.
All of this is why accelerometers are never used for distance calculations. If you want distance, use GPS or network based location. Either will be far more correct than the accelerometer.
Now you say you want to measure to an accuracy of .15m. I don't think there's any way to do that. GPS isn't that accurate even under open sky conditions- that's about 5m with perfect atmospheric conditions. Maybe classified military hardware can come close, but on a commercial phone expect more like 10m, and with occasional jumps of 100m if in a downtown location or in mountains, and >5m if inside. If you want to do it at a specific location you could set up BLE beacons and use distance triangulation off of them, but even that is unlikely to get you that degree of accuracy. They technology just isn't made for it.
You mention ARCore- ARCore does something very different. When it measures distance, it doesn't know anything about its location in the world. It uses computer vision to try to figure out where objects are in an image, and then estimates distance to that object. IT doesn't detect movement of a phone at all (well, it does have a mode where it will use GPS to allow you to place objects at a GPS coordinate, but that's a totally different subsystem of ARCore).