使用线性加速度计算距离的Android应用

10
我将使用以下代码来计算距离。 tnewanew 是包含时间戳加速度arraylists
 double distance=0;
 double init_vel=0;
long time_prev=tnew.next();
   while(anew.hasNext())
   {
    float temp_acc=anew.next();
    long temp_time=tnew.next();

    interval=(temp_time-time_prev)/1000f;   //milliseconds to seconds
    double fin_vel=init_vel+(temp_acc*interval);
    distance+=(init_vel*interval)+0.5f*temp_acc*interval*interval;

    init_vel=fin_vel;
    time_prev=temp_time;
   }


这段代码中有逻辑错误吗?因为我得到的值比实际长度小得多。

LogCat 的输出结果:

--------- beginning of /dev/log/system

--------- beginning of /dev/log/main

V/PhonetapeActivity( 8842): Sensor Listener Registered

V/PhonetapeActivity( 8842): Sensor Unregistered

V/PhonetapeActivity( 8842): No. of Iterations : 49

V/PhonetapeActivity( 8842): Value of acceleration : 3.5762787E-7

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665585965

V/PhonetapeActivity( 8842): Value of acceleration : -0.15275347

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665586017

V/PhonetapeActivity( 8842): Value of acceleration : 0.15585232

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665586077

V/PhonetapeActivity( 8842): Value of acceleration : 1.075269

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665586138

V/PhonetapeActivity( 8842): Value of acceleration : 3.6529458

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665586199

V/PhonetapeActivity( 8842): Value of acceleration : 9.645137

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665586257

V/PhonetapeActivity( 8842): Value of acceleration : 17.022213

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665586316

V/PhonetapeActivity( 8842): Value of acceleration : 9.721476

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665586376

V/PhonetapeActivity( 8842): Value of acceleration : -18.729362

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665586437

V/PhonetapeActivity( 8842): Value of acceleration : -22.868385

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665586497

V/PhonetapeActivity( 8842): Value of acceleration : -16.777517

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665586557

V/PhonetapeActivity( 8842): Value of acceleration : -7.0492268

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665586617

V/PhonetapeActivity( 8842): Value of acceleration : -3.860828

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665586677

V/PhonetapeActivity( 8842): Value of acceleration : 1.7244682

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665586737

V/PhonetapeActivity( 8842): Value of acceleration : 5.0734243

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665586797

V/PhonetapeActivity( 8842): Value of acceleration : 6.4193974

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665586857

V/PhonetapeActivity( 8842): Value of acceleration : 2.739545

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665586917

V/PhonetapeActivity( 8842): Value of acceleration : 5.559997

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665586977

V/PhonetapeActivity( 8842): Value of acceleration : 4.2290807

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665587037

V/PhonetapeActivity( 8842): Value of acceleration : 5.0012918

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665587097

V/PhonetapeActivity( 8842): Value of acceleration : 5.9317436

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665587157

V/PhonetapeActivity( 8842): Value of acceleration : 5.20226

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665587217

V/PhonetapeActivity( 8842): Value of acceleration : 7.1381693

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665587276

V/PhonetapeActivity( 8842): Value of acceleration : 7.6460614

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665587337

V/PhonetapeActivity( 8842): Value of acceleration : 5.566694

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665587396

V/PhonetapeActivity( 8842): Value of acceleration : 3.355657

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665587457

V/PhonetapeActivity( 8842): Value of acceleration : 1.8876343

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665587517

V/PhonetapeActivity( 8842): Value of acceleration : -0.8815446

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665587577

V/PhonetapeActivity( 8842): Value of acceleration : -0.9595623

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665587646

V/PhonetapeActivity( 8842): Value of acceleration : -4.233544

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665587697

V/PhonetapeActivity( 8842): Value of acceleration : -1.9580669

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665587765

V/PhonetapeActivity( 8842): Value of acceleration : -1.4569702

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665587822

V/PhonetapeActivity( 8842): Value of acceleration : -0.6058636

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665587876

V/PhonetapeActivity( 8842): Value of acceleration : -0.21207428

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665587937

V/PhonetapeActivity( 8842): Value of acceleration : 0.5068469

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665587997

V/PhonetapeActivity( 8842): Value of acceleration : 5.614555

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665588057

V/PhonetapeActivity( 8842): Value of acceleration : -4.5297813

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665588122

V/PhonetapeActivity( 8842): Value of acceleration : -0.29250193

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665588178

V/PhonetapeActivity( 8842): Value of acceleration : -2.4922757

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665588237

V/PhonetapeActivity( 8842): Value of acceleration : -1.7652755

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665588297

V/PhonetapeActivity( 8842): Value of acceleration : -2.3279366

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665588357

V/PhonetapeActivity( 8842): Value of acceleration : -1.8127642

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665588419

V/PhonetapeActivity( 8842): Value of acceleration : -1.956768

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665588477

V/PhonetapeActivity( 8842): Value of acceleration : -0.8337221

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665588537

V/PhonetapeActivity( 8842): Value of acceleration : -0.24841261

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665588601

V/PhonetapeActivity( 8842): Value of acceleration : 0.23997736

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665588657

V/PhonetapeActivity( 8842): Value of acceleration : 0.14441395

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665588723

V/PhonetapeActivity( 8842): Value of acceleration : 0.23150349

V/PhonetapeActivity( 8842): Value of timestamp(milli) : 1350665588777

V/PhonetapeActivity( 8842):  1st while loop ended

V/PhonetapeActivity( 8842): 2nd while loop ended

V/PhonetapeActivity( 8842): Avg value : 0.4006781578063965

V/PhonetapeActivity( 8842): Max Value : 17.022213

V/PhonetapeActivity( 8842): Min Value : -22.868385

V/PhonetapeActivity( 8842): Standard Deviation : -0.0031174493

V/PhonetapeActivity( 8842): 3rd while loop started

V/PhonetapeActivity( 8842): startpos=3 endpos=8

V/PhonetapeActivity( 8842): acceleration=0.1558523178100586 interval=0.061000000685453415

V/PhonetapeActivity( 8842): distance=5.799264876044276E-4

V/PhonetapeActivity( 8842): next init velocity=0.009506991493243078

V/PhonetapeActivity( 8842): acceleration=1.0752689838409424 interval=0.061000000685453415

V/PhonetapeActivity( 8842): distance=0.005160928954000712

V/PhonetapeActivity( 8842): next init velocity=0.07509840024458736

V/PhonetapeActivity( 8842): acceleration=3.6529457569122314 interval=0.057999998331069946

V/PhonetapeActivity( 8842): distance=0.021805144861910285

V/PhonetapeActivity( 8842): next init velocity=0.2869692480489858

V/PhonetapeActivity( 8842): acceleration=9.645136833190918 interval=0.05900000035762787

V/PhonetapeActivity( 8842): distance=0.07231105232279186

V/PhonetapeActivity( 8842): next init velocity=0.8560323246566197

V/PhonetapeActivity( 8842): acceleration=17.022212982177734 interval=0.05999999865889549

V/PhonetapeActivity( 8842): distance=0.18495295465057213

V/PhonetapeActivity( 8842): next init velocity=1.8773650807587172

V/PhonetapeActivity( 8842): 3rd while loop ended

V/PhonetapeActivity( 8842): final distance=0.18495295465057213

V/PhonetapeActivity( 8842): values of acceleration, timestamp, distance, start_time and calibrating reset

如果您观察logcat,首先它会迭代49个加速度值及其对应的时间戳(以毫秒为单位)。然后有一个平均值、总和、最大值、最小值等等。接着,如果您看到startpos=3endpos=8,这是我用来计算距离的迭代次数范围,即我仅使用从第三个到第八个迭代中的加速度和时间戳的值。这是因为我检测到距离计算的开始是从加速度上升方向突然改变。您可以看到3-8的值符合这个逻辑。从3开始,加速度显著上升,在8之后突然下降。

我没有看到写着他在双重积分之后得到准确结果的地方(这是你试图做的事情)。 - Ali
我认为这不会起作用,可以在我的第一条评论中的链接中看到原因。 - Ali
你用哪个安卓设备来测试这个? - TheCodeArtist
@TheCodeArtist:三星Galaxy ACE。 - Ashwin
话虽如此,每秒16个样本(@poll-rate=60ms)本身就相对不准确。您可能希望尝试使用SENSOR_DELAY_FASTEST注册sensorEventListner,以查看您的设备可以获取的最大样本数。 - TheCodeArtist
显示剩余9条评论
3个回答

6
Accelerometers非常精确,但在航位推算方面效果不佳。陀螺仪在这方面很好,但随着时间的推移会“漂移”。 "Sensor-fusion"是使用加速度计/陀螺仪数据并肩工作以纠正彼此缺陷的过程。据我所知,Galaxy Ace上未启用“sensor-fusion”。LINEAR_ACCELERATION只是ACCELEROMETER - 重力分量。在没有陀螺仪的设备上,融合不可能,因为它需要加速度计和陀螺仪。加速度计数据包含9.8的重力分量。通过简单地确定两个连续加速度计数据样本之间的差异来过滤掉这些内容。这给我们带来了LINEAR_ACCELERATION数据。

查看实际内部代码:
frameworks/base/services/sensorservice/LinearAccelerationSensor.cpp
上述文件中的函数LinearAccelerationSensor::process()很有意思。

此外,像上面的链接和视频所讲述的那样进行滤波/平均等基本操作,需要在您的应用程序中对加速度数据进行处理。以这种方式获得的处理后的值将比原始值更好(尽管不如设备上存在传感器融合时获得的值好)。然后可以使用这些值更准确地计算速度和位置。

话虽如此,每秒16个样本(@poll-rate=60ms)本身就相对不准确。您可能希望尝试使用SENSOR_DELAY_FASTEST注册sensorEventListner,以查看您的设备可以获取的最大样本数。

请注意,手机上的加速度计被夹紧到一定的最大灵敏度范围内(通常为-/+2/4/8 G范围)。虽然正常步行/奔跑可能在这些范围内操作,但是加速度突然增加(例如在自行车上)肯定会被夹紧到最大值,你将失去死推导航的同步。可以通过注意非常接近-/+MAX的样本数量来检查这一点。许多样本在-/+MAX意味着您肯定已经与实际位置失去了同步。

感谢您将评论发布为答案。但是您说Galaxy ACE上未启用传感器融合。但是LINEAR_ACCELERATION在我的手机(ACE)上可以使用。LINEAR_ACCELERATION是传感器融合的结果。它使用两个或更多传感器来提供线性加速度。 - Ashwin
1
LINEAR_ACCELERATION 就是 ACCELEROMETER 去除重力分量后的结果。在没有陀螺仪的设备上,由于定义需要加速度计和陀螺仪才能进行融合,因此无法实现。 - TheCodeArtist
要找出重力分量,您需要一个陀螺仪。它提供了手机的方向,并相应地移除重力分量。 - Ashwin
不,陀螺仪并非绝对必要的。更新答案以描述“线性加速度”传感器的内部情况,即在将加速度计数据报告为线性加速度之前所做的处理。 - TheCodeArtist
1
假设你在短暂的瞬间内加速非常快,达到了+3g的级别。但是加速度计被配置为- / + 2g的范围,这意味着它将报告+2g(而实际上你处于+3g)。因此,你的实际位置和计算位置将有所不同,没有真正的方法来纠正这种情况。只能检测到它;因为如果你得到很多最大限制值,那么你超过它的机会就更大。再次提醒,当设备在手中且用户步行时,这样“大”的加速度并不常见。但是,无论如何,你需要意识到这个陷阱。 - TheCodeArtist
显示剩余2条评论

4

我首先要检查的是你的时间间隔。我不确定它是否被正确地转换了。时间戳列如下:

public long timestamp 事件发生时的纳秒时间

因此在文档中,我们可以看到通过除以10亿而不是1千来进行转换。

float dT = (event.timestamp - timestamp) / 1000000000.0f;
timestamp = event.timestamp;

尽管如此,我认为这种变化只会缩小数值,但要计算现实世界的距离,您需要注意单位。

接下来,在阅读与这些事情有关的内容时,人们总是会谈论你需要知道每个读数的初始位置才能将其与现实世界的线性测量联系起来。我没有看到您在跟踪先前的加速度,这将使得每个后续测量的积分基于瞬时加速度或加速度变化,而不是全加速度。

可以尝试像这样:

final int X = 0;
double distance[];
double init_vel[];
double total_Accel[];

void dblIntegrate(SensorEvent event){
    double data[] = new double[3];
    for(int i = 0; i < event.lenght; i++){
        data[i] = (double)event[i];
        total_Accel[i] += data[i];
        vel[i] = init_vel[i] + (total_Accel[i] * dt);
        init_vel[i] = vel[i];

        ....rinse and repeate to get distance
        (not using the accel data of course)
    }
}

我知道您已经理解了这一点,但是对于其他人来说,请记住每次调用dblIntegrate()时都不能重新实例化计数变量total_Accel或init_vel。
如果您做得正确,您应该看到total_Accel从零到某个最大值,然后每当设备移动时就返回零。这意味着每次设备向任何方向移动时,您都会添加相等部分的正加速度和负加速度。
我认为这是加速度中最难正确理解的属性,因为为了使设备从静止状态到静止状态,您的总加速度将从零达到最大正/负值,然后回到零到相反的最大值,然后再回到零。
例如,如果我将手机从胸部朝右放在桌子上,移动一米,您将得到如下结果:
total_Accel = 0.0(0米) total_Accel = 0.5 total_Accel = 1.0 total_Accel = 1.5(约为0.25米) total_Accel = 1.0 total_Accel = 0.5 total_Accel = 0.0(如果加速度完全分布,则为0.5米) total_Accel = -0.5 total_Accel = -1.0 total_Accel = -1.5(约为0.75米) total_Accel = -1.0 total_Accel = -0.5 total_Accel = 0.0(1米)
在这个例子中,您可以开始看到为什么简单地对加速度变化进行双重积分不会给出真实的速度/位移变化。
希望这样讲解有帮助,因为写这篇文章花费的时间比我想象的要长得多!:)

我还没有完全阅读完这篇文章。但是关于时间戳,我使用了System.currentMillis()。根据Android文档中delay_sensor_ui的规定,我得到了60毫秒的时间间隔。 - Ashwin
抱歉关于时间戳信息的问题。我已经在过去一个月里艰难地处理这些东西,我认为所有的传感器都是以相同的单位报告时间。在给出错误答案之前,我应该再次核实我的事实。我确实检查了SensorEvent event.timestamp文档,并且它说它是以纳秒为单位的,但这是针对API Level 3的,所以可能混淆来自那里。我很抱歉我不能更具体,但希望其他人能够发表意见。 - BluMo.us
你是将每个测量输出到CSV文件吗?如果在任何过滤之前和之后能看到所有变量(传感器读数,速度,dT和位移)的输出,那将会非常有帮助。我已经花了很多时间查看我的数据:),也许我会发现一些有用的东西。 - BluMo.us
你真的需要提高采样速度。你正在失去很多数据。一个时间间隔从9.7到-17.7。我不知道你如何在这么短的时间内产生近30G的力量,但你应该在某个地方看到它。但我最担心的是为什么你的值这么大。你在发送日志之前是否对它们进行了操作?如果没有,可能是你的传感器或读取传感器的软件出了问题,因为当我摇晃手机时,很少看到超过3-3.5G的值。话虽如此,我会处理数据,并在稍后(6-7小时)放入另一个答案中。 - BluMo.us
2
嘿伙计们,有点晚了,但可以有人解释一下他在最后说“没有加速度计数据重复洗涤”的那部分吗? - erik
显示剩余15条评论

2

这是对您问题的回答:

为什么我需要追踪之前的加速度。onSensorChanged(MotionEvent事件){}在加速度发生变化时被调用。它提供新的加速度而不是加速度的变化。

简短的回答是,如果在不包括初始条件(您之前的总加速度)的情况下进行读取集成,您最终会得到一个不包含所有信息的值。此外,您积累越久,您的值与真实值之间的差距就越大,因为您丢失了越来越多的信息。

我认为您不需要关于加速度,速度和位移的解释(这不是那个地方),因此也许我可以通过扩展上面提供的示例来展示它。

一部手机背朝桌面,底部朝向我的胸口,被移动到右侧一段任意距离后停下。如果您查看数据,您会得到类似于以下内容的结果。当然,实际数字会有很大的差异,但它们的符号将是相同的,比例也会类似,但开始时会比峰值小,就像您所期望的那样(除非您用枪射出并撞上墙壁或其他障碍物):
时间........加速度读数........总加速度........总速度 00ms..............0.0......................0.0.......................0.000 10ms..............0.5......................0.5.......................0.005 m/s 20ms..............0.5......................1.0.......................0.015 m/s 30ms.............0.5......................1.5.......................0.030 m/s 40ms.............-0.5......................1.0.......................0.040 m/s 50ms.............-0.5......................0.5.......................0.045 m/s 60ms.............-0.5......................0.0.......................0.045 m/s 70ms.............-0.5.....................-0.5.......................0.040 m/s 80ms.............-0.5.....................-1.0.......................0.030 m/s 90ms.............-0.5.....................-1.5.......................0.015 m/s 100ms.............0.5.....................-1.0.......................0.005 m/s 110ms.............0.5.....................-0.5.......................0.000 m/s 120ms.............0.5......................0.0.......................0.000 m/s
您可以看到,如果您不跟踪总加速度,则总速度将是上面标记为Total Accel的列。这意味着您的手机在整个移动过程中将向x轴正方向移动,但您的速度将在后半段(向后移动)变为负数。
希望这证明了我的观点,即使它没有解释加速度或加速计背后的机制。如果您想查找加速计的工作原理,它们是MEMS类型的传感器,我认为它们使用悬挂式悬臂梁和带有加权端的测量加速度力。

请问能提供一些代码实现吗? - Gevaria Purva

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接