【问题标题】:Integrating Android Accelerometer to Find Velocity and Position集成 Android 加速度计以查找速度和位置
【发布时间】:2015-05-25 18:00:16
【问题描述】:

我正在尝试使用 Android 设备 (Sensor.TYPE_LINEAR_ACCELERATION) 上的加速度计计算位移。这是我的OnSensorChanged() 方法:

public void onSensorChanged(SensorEvent event) {
    accelX = event.values[0];
    accelY = event.values[1];
    accelZ = event.values[2];

    long currentTime = System.currentTimeMillis() / 1000;

    if(prevTime == 0) prevTime = currentTime;

    long interval = currentTime - prevTime;
    prevTime = currentTime;     

    velX += accelX * interval;
    velY += accelY * interval;
    velZ += accelZ * interval;

    distX += prevVelX + velX * interval;
    distY += prevVelY + velY * interval;
    distZ += prevVelZ + velZ * interval;

    prevAccelX = accelX;        
    prevAccelY = accelY;        
    prevAccelZ = accelZ;

    prevVelX = velX;
    prevVelY = velY;
    prevVelZ = velZ;
}

但是,速度不会在任何形式的移动后返回 0。除非非常突然,否则减速几乎没有影响。这会导致一些非常不准确的距离值。

加速度计也很吵,所以我加了这个:

accelX = (accelX * accelKFactor) + prevAccelX * (1 - accelKFactor);
accelY = (accelY * accelKFactor) + prevAccelY * (1 - accelKFactor);
accelY = (accelX * accelKFactor) + prevAccelY * (1 - accelKFactor);

accelKFactor = .01

我是否遗漏了一些明显的东西?

我的最终目标只是能够判断设备是否移动了超过 10 英尺,但现在,我的数据几乎没有用。

编辑:

我发现了部分问题。 currentTime 很长,但我将系统时间(以毫秒为单位)除以 1000 以获得秒数。所以速度只能真正每 1 秒更新一次。将 currentTime 更改为 double 会有所帮助,但并不能完全解决问题。

【问题讨论】:

  • 不幸的是,仅通过加速度的双重积分来跟踪位置是不切实际的。即使是非常昂贵的商业惯性导航系统也会以每秒一英尺的速度漂移。手机中的商品传感器会更糟。您的问题可能重复是here
  • 感谢@rhashimoto 的评论。我明白你在说什么,但我的目标只是能够确定设备是否移动了 10 英尺以上。因此,我不需要太多的准确性。我只是希望从加速度数据中找出某种意义。
  • 我认为您无法判断设备没有移动了 10 英尺,即它总是认为它正在缩小到某个地方。但也许你会想出一些聪明的东西。突破是由那些忽视他们被告知是“不可能的”的人取得的:-)。

标签: java android accelerometer


【解决方案1】:

SensorEvent 有一个时间戳字段,它是以纳秒为单位的时间。使用它而不是 System.currentTimeMillis()。这是文档中的一个示例:

private static final float NS2S = 1.0f / 1000000000.0f;
 private float timestamp;

 public void onSensorChanged(SensorEvent event) {
      // This timestep's delta rotation to be multiplied by the current rotation
      // after computing it from the gyro sample data.
      if (timestamp != 0) {
          final float dT = (event.timestamp - timestamp) * NS2S;

以这种方式跟踪位移对初始条件非常敏感,因此应该会有所帮助。

另外,使用 Location.getSpeed() 可能会更好。如果您无法获得信号,请考虑仅将加速度计用作备用。

【讨论】:

  • 啊,纳秒分辨率更有帮助。数据仍然远非完美,但我接受了这个答案,因为我不确定我能得到多少。不过我会继续玩它一段时间。
  • 另外,我同意 Location.getSpeed() 是个好主意,但正如我在问题中提到的,我至少需要
【解决方案2】:

请检查以下代码

public class MainActivity extends Activity implements SensorEventListener {
    private SensorManager sensorManager;
    float appliedAcceleration = 0;
    float currentAcceleration = 0;
    float velocity = 0;
    Date lastUpdatedate;
    double calibration = Double.NaN;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        lastUpdatedate = new Date(System.currentTimeMillis());
        sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        double x = event.values[0];
        double y = event.values[1];
        double z = event.values[2];
        double a = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2));
        if (calibration == Double.NaN)
            calibration = a;
        else {
            Date timeNow = new Date(System.currentTimeMillis());
            long timeDelta = timeNow.getTime()-lastUpdatedate.getTime();
            lastUpdatedate.setTime(timeNow.getTime());
            float deltaVelocity = appliedAcceleration * (timeDelta/1000);
            appliedAcceleration = currentAcceleration;
            velocity += deltaVelocity;
            final double mph = (Math.round(100*velocity / 1.6 * 3.6))/100;
            Log.i("SensorTestActivity","SPEEDDDDD=== "+mph+"     "+velocity);
            currentAcceleration = (float)a;
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }

    @Override
    protected void onStart() {
        super.onStart();
        sensorManager.registerListener(this,
                sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    protected void onStop() {
        super.onStop();
        sensorManager.unregisterListener(this);
    }
}

【讨论】:

    猜你喜欢
    • 2011-06-28
    • 1970-01-01
    • 2011-08-25
    • 1970-01-01
    • 1970-01-01
    • 2011-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多