使用Android实现陀螺仪和加速度计的互补滤波器

7

最近我进行了一些研究,使用加速度计和陀螺仪来跟踪智能手机,而不需要GPS的帮助(请参见此帖子)基于陀螺仪和加速度计的室内定位系统

为此,我需要我的方向(角度(俯仰,横滚等)),所以这是我迄今为止所做的:

public void onSensorChanged(SensorEvent arg0) {
    if (arg0.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
    {
        accel[0] = arg0.values[0];
         accel[1] = arg0.values[1];
   accel[2] = arg0.values[2];
   pitch = Math.toDegrees(Math.atan2(accel[1], Math.sqrt(Math.pow(accel[2], 2) + Math.pow(accel[0], 2))));

  tv2.setText("Pitch: " + pitch + "\n" + "Roll: " + roll);

   } else if (arg0.sensor.getType() == Sensor.TYPE_GYROSCOPE )
{
  if (timestamp != 0) {
  final float dT = (arg0.timestamp - timestamp) * NS2S;         
  angle[0] += arg0.values[0] * dT;
  filtered_angle[0] = (0.98f) * (filtered_angle[0] + arg0.values[0] * dT) + (0.02f)* (pitch);
   }        
   timestamp = arg0.timestamp;
 }
}

在这里,我正在尝试从我的加速度计(俯仰)角度(仅用于测试),通过时间积分陀螺仪_X并使用互补滤波器进行过滤来倾斜。

filtered_angle[0] = (0.98f) * (filtered_angle[0] + gyro_x * dT) + (0.02f)* (pitch)

dT 大约为 0.009 秒

但是我不知道为什么我的角度并不是非常准确... 当设备平放在桌子上(显示面向上)时。

Pitch (angle fromm accel) = 1.5 (average) 
Integrate gyro = 0 to growing (normal it's drifting) 
filtered gyro angle = 1.2

当我将手机向上抬起90度时(屏幕朝着我面前的墙),

Pitch (angle fromm accel) = 86 (MAXIMUM) 
Integrate gyro = he is out ok its normal 
filtered gyro angle = 83 (MAXIMUM)

因此,角度永远不会达到90度吗?即使我试图再将手机举高一点……为什么它不能达到90度?我的计算有误吗?还是传感器的质量很差?
另一件让我感到疑惑的事情是:在Android上,我没有“读取”传感器的值,但当它们发生变化时我会收到通知。问题在于,如您在代码中所见,加速度计和陀螺仪共享同一方法……因此,当我计算滤波后的角度时,我会提前0.009秒测量加速度计的俯仰角度,对吗?这可能是我的问题源头吗?
谢谢!

1
可能是重复的问题:基于陀螺仪和加速度计的室内定位系统 - Potatoswatter
4个回答

5
我只能重复自己。 通过两次积分来获得位置,但是误差非常大,实际上没有用。换句话说,你正在试图解决不可能的问题。
你实际上可以追踪方向。
横滚、俯仰和偏航是有问题的,请不要使用它们。在我已经推荐的视频中,在38:25处检查。
这是一个关于如何使用陀螺仪和加速度计跟踪方向的优秀教程。 类似的问题可能会对你有所帮助:

不需要GPS也能追踪iPhone微小的移动
手机加速度计在定位时的真实精度是多少?
如何计算手机从静止状态开始在垂直方向上的运动?
iOS:在三维空间中的运动精度
如何使用加速度计来测量Android应用程序开发的距离
由加速度计移动的距离
如何使用陀螺仪和加速度计找到行驶距离?


谢谢你的帮助,很抱歉让你重复做一些事情。 确实,gentlnav教程非常好!我刚刚快速阅读了它,它很好地解释了DCM,我会仔细阅读它。我在stackoverflow上找到了一个类似的问题,你在那里谈论了同样的教程,并且你说你在人体运动感应中使用它。那么这意味着你成功地使用DCM获得了不错的方向吗? https://dev59.com/rVXTa4cB1Zd3GeqPzj3r谢谢 - Alexis
@Alexis 没问题,祝你好运!是的,我有一个C++实现,但在Java中为Android编写自己的实现并不太困难。也许存在现有的应用程序,但很遗憾我不知道任何。对于你的应用程序来说,仅仅是方向感足够了吗? - Ali
由于这只是我的学校项目,我只是想知道是否可能。经过大量阅读,我发现不可能 :) 或者如果可能的话,那已经超出了我的数学理解范围...所以我只是打算稍微改变一下,并尝试使用陀螺仪+加速度计来获取方向 :) - Alexis
我刚发现这篇文章:http://www.diydrones.com/profiles/blogs/a-simple-deadreckoning,它使用DCM+航位推算来跟踪飞机(他两次积分得到位置,但我不理解他如何纠正结果)。 - Alexis
@Alexis 我没有检查细节,但我觉得他的算法是基于GPS的,IMU用于“填补空白”。是的,你可以用卡尔曼滤波器来做到这一点,但在你的问题中,你说你没有使用GPS。 - Ali
@Ali感谢您的解释,您能指导我关于这个问题吗?http://stackoverflow.com/questions/27137239/get-moving-device-direction-without-gps - Arash

3

0

我测试了你的代码,发现可能比例因子不一致。 将音高转换为0-pi可以得到更好的结果。 在我的测试中,滤波后的结果约为90度。

pitch = (float) Math.toDegrees(Math.atan2(accel[1], Math.sqrt(Math.pow(accel[2], 2) + Math.pow(accel[0],   2))));
pitch = pitch*PI/180.f;

filtered_angle = weight * (filtered_angle + event.values[0] * dT) + (1.0f-weight)* (pitch);

-1

我尝试过,这将给你90度的角度...

filtered_angle = (filtered_angle / 83) * 90;

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