如何计算安卓手机从手中掉落时的垂直行驶距离?



所以我使用加速度计来检查手机是否掉落。这部分工作得很好。

我出于上述目的使用了下面给出的链接。 https://github.com/altermarkive/experimental-fall-detector-android-app

现在下一步是计算它垂直行进的距离。
为此,我尝试了很多方法,但每次高度都不正确。
此外,不同设备上的高度也不同。

我从加速度计传感器获取加速度数据,之后我使用以下给定的公式来计算行驶距离。

我尝试的第一个代码:-

long curTime = System.currentTimeMillis();
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
// sampling frequency f= 10Hz.
if ((curTime - lastUpdate) > CHECK_INTERVAL) {
long diffTime = (curTime - lastUpdate);
lastUpdate = curTime;
accel_values = event.values.clone();
if (last_accel_values != null) {
mAccelLast = mAccelCurrent;
mAccelCurrent =(float)Math.sqrt(accel_values[0]* accel_values[0] + 
accel_values[1]*accel_values[1]
+ accel_values[2]*accel_values[2]);
Message msg = mHandler.obtainMessage(Constants.MESSAGE_CHANGED);
Bundle bundle = new Bundle();
bundle.putFloat(Constants.VALUE, mAccelCurrent);
msg.setData(bundle);
mHandler.sendMessage(msg);
mWindow.add(mAccelCurrent);
if (mWindow.isFull() && mWindow.isFallDetected()){
Log.w(TAG, "Fall detected by window class");
actime = curTime - diffTime;
velocity = actime * acceleration;
avgvelocity = velocity / 2;
height = avgvelocity * actime;
mWindow.clear();
msg = mHandler.obtainMessage(Constants.MESSAGE_EMERGENCY);
mHandler.sendMessage(msg);
}
}
last_accel_values = accel_values.clone();
}
}

我尝试的第二个代码:-

final double alpha = 0.8;
double gravity[] = new double[3], linear_acceleration[] = new double[3];
// Isolate the force of gravity with the low-pass filter.
gravity[0] = alpha * gravity[0] + (1 - alpha) * sensorEvent.values[0];
gravity[1] = alpha * gravity[1] + (1 - alpha) * sensorEvent.values[1];
gravity[2] = alpha * gravity[2] + (1 - alpha) * sensorEvent.values[2];
double curr_gravity = gravity[0] + gravity[1] + gravity[2];
// Remove the gravity contribution with the high-pass filter.
linear_acceleration[0] = sensorEvent.values[0] - gravity[0];
linear_acceleration[1] = sensorEvent.values[1] - gravity[1];
linear_acceleration[2] = sensorEvent.values[2] - gravity[2];
double curr_acc = linear_acceleration[0] + linear_acceleration[1] + linear_acceleration[2];
long seconds = System.currentTimeMillis();
double velocity = curr_acc * seconds;
double init_vel = velocity / 2;
double time = (velocity - init_vel) / curr_gravity;
double height = (((seconds * 9.8)/2) - init_vel);

我尝试的第三个公式:-

long curTime = System.currentTimeMillis();

if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
// sampling frequency f= 10Hz.
if ((curTime - lastUpdate) > CHECK_INTERVAL) {
long diffTime = (curTime - lastUpdate);
lastUpdate = curTime;
accel_values = event.values.clone();
if (last_accel_values != null) {
mAccelLast = mAccelCurrent;
mAccelCurrent =(float)Math.sqrt(accel_values[0]* accel_values[0] + 
accel_values[1]*accel_values[1]
+ accel_values[2]*accel_values[2]);
Message msg = mHandler.obtainMessage(Constants.MESSAGE_CHANGED);
Bundle bundle = new Bundle();
bundle.putFloat(Constants.VALUE, mAccelCurrent);
msg.setData(bundle);
mHandler.sendMessage(msg);
mWindow.add(mAccelCurrent);
if (mWindow.isFull() && mWindow.isFallDetected()){
Log.w(TAG, "Fall detected by window class");
actime = curTime - diffTime;
height = 0.5*9.8*actime*actime;
mWindow.clear();
msg = mHandler.obtainMessage(Constants.MESSAGE_EMERGENCY);
mHandler.sendMessage(msg);
}
}
last_accel_values = accel_values.clone();
}
}

第四个公式和当前使用的代码:-

public void onSensorChanged(SensorEvent event) {
long curTime = System.currentTimeMillis();
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
// sampling frequency f= 10Hz.
if ((curTime - lastUpdate) > CHECK_INTERVAL) {
lastUpdate = curTime;
accel_values = event.values.clone();
if (last_accel_values != null) {
mAccelLast = mAccelCurrent;
final double alpha = 0.8;
double gravity[] = new double[3], linear_acceleration[] = new double[3];
gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0];
gravity[1] = alpha * gravity[1] + (1 - alpha) * event.values[1];
gravity[2] = alpha * gravity[2] + (1 - alpha) * event.values[2];
linear_acceleration[0] = event.values[0] - gravity[0];
linear_acceleration[1] = event.values[1] - gravity[1];
linear_acceleration[2] = event.values[2] - gravity[2];
double mAccelCurrent = linear_acceleration[0] + linear_acceleration[1] + linear_acceleration[2];
double loX = event.values[0];
double loY = event.values[1];
double loZ = event.values[2];
double loAccelerationReader = Math.sqrt(Math.pow(loX, 2)
+ Math.pow(loY, 2)
+ Math.pow(loZ, 2));
DecimalFormat precision = new DecimalFormat("0.00");
double ldAccRound = Double.parseDouble(precision.format(loAccelerationReader));
// Send the value back to the Activity
Message msg = mHandler.obtainMessage(Constants.MESSAGE_CHANGED);
Bundle bundle = new Bundle();
bundle.putFloat(Constants.VALUE, (float) mAccelCurrent);
msg.setData(bundle);
mHandler.sendMessage(msg);
mWindow.add((float) mAccelCurrent);
if (mWindow.isFull() && mWindow.isFallDetected() && ldAccRound > 12d) {
long stop = System.currentTimeMillis();
Log.e(TAG, "Fall detected by window class");
long time = stop - curTime;
double currtime1 = (double) time / 1000;
velocity = currtime1 * mAccelCurrent;
height = velocity * currtime1 * currtime1;
Log.e("Height", "Vel : " + velocity + ", Avg : " + avgvelocity + ", Height : " +
height);
mWindow.clear();
if (height > 0) {
AppPreferences.setFall(context, String.valueOf(height));
/*mAccelCurrent = 0;
velocity = 0;
avgvelocity = 0;
height = 0;*/
msg = mHandler.obtainMessage(Constants.MESSAGE_EMERGENCY);
mHandler.sendMessage(msg);
} else
Toast.makeText(context, "Height not calculated properly. Please drop again",
Toast.LENGTH_LONG).show();
}
}
last_accel_values = accel_values.clone();
}
}
}

我还尝试将其他传感器用于相同的目的,例如气压计,但我从它们那里得到了相同的结果(高度没有按预期而来)。
另外,我尝试寻找第三方SDK,但他们也使用自己的硬件。
任何形式的帮助将不胜感激。此外,如果有人能以正确的方式指导,那将非常有帮助。

提前谢谢。

似乎您在所有三种方法中都犯了相同的错误。在所有三个中,在某些时候,您将加速度乘以System.currentTimeMillis()的绝对时间戳。这是自 1970 年以来的毫秒,在您的情况下没有直接意义,除非您使用它来计算时间间隔作为差值。在某些示例中,您这样做,但您再次从System.currentTimeMillis()中减去它,这再次导致自 1970 年以来的毫秒数。

看起来您尝试实现 s = 1/2 a t²,但这仅适用于在时间间隔 t 内从静止开始的恒定加速度。如果要从测量加速度序列中得出距离,则需要对它们进行数字积分(这听起来比实际更难),并且可能希望使用一些过滤。

但是,我的建议是简单地假设加速度为9.81 m/s²的自由落体。这忽略了空气阻力或地球加速度的局部变化,但除非你想在一些奇怪的情况下使用它,否则这可能比使用传感器的读数要精确得多。从空间上讲,当手机旋转时,但也由于校准不良和一些过滤将实际加速度与重力加速度分开,我不希望传感器读数优于近似完美的自由落体。毕竟,智能手机是相当密集的物体,受空气阻力的影响不大。

好处是您可以简单地使用 s = 1/2 a t²。只要确保 t 不是自 1970 年以来的时间间隔,而是从下降开始(你说你可以可靠地检测到)到下降结束的计时器间隔(即开始时时间戳和结束时时间戳的差异)。此外,我建议使用传感器事件中的时间而不是System.currentTimeMillis()因为它具有更好的分辨率并且专为这种类型的计算而设计。

最新更新