jjzjj

android - 如何以稳定准确的方式读取Android加速度计值?

coder 2023-12-25 原文

在我的项目中,我试图使用通过 Android 设备的加速度计获得的数据来控制汽车。 (左、右、前进、后退)。即使我已经设法从加速度计读取值,即使设备处于稳定位置,读数也会频繁变化。有人可以为我提供更好的方法吗?

以下是我用过的代码

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;

public class AccelerometerService {
    private static SensorManager sensorManager;
    private static SensorEventListener sensorEventListener;
    private static boolean started = false;

    private static float[] accelerometer = new float[3];
    private static float[] magneticField = new float[3];

    private static float[] rotationMatrix = new float[9];
    private static float[] inclinationMatrix = new float[9];
    private static float[] attitude = new float[3];

    private final static double RAD2DEG = 180/Math.PI;

    private static int initialAzimuth = 0;
    private static int initialPitch = 0;
    private static int initialRoll = 0;

    private static int[] attitudeInDegrees = new int[3];

    public static void start(final Context applicationContext) {
        if(started) {
            return;
        }

        sensorManager = (SensorManager) applicationContext
                .getSystemService(Context.SENSOR_SERVICE);

        sensorEventListener = new SensorEventListener() {

            @Override
            public void onSensorChanged(SensorEvent event) {

                int type = event.sensor.getType();
                if(type == Sensor.TYPE_MAGNETIC_FIELD) {
                    magneticField = event.values.clone();
                } 
                if(type == Sensor.TYPE_ACCELEROMETER) {
                    accelerometer = event.values.clone();
                }

                SensorManager.getRotationMatrix(rotationMatrix, inclinationMatrix, accelerometer, magneticField);
                SensorManager.getOrientation(rotationMatrix, attitude);

                attitudeInDegrees[0] =  (int) Math.round(attitude[0] * RAD2DEG);    //azimuth
                attitudeInDegrees[1] = (int) Math.round(attitude[1] * RAD2DEG);     //pitch
                attitudeInDegrees[2] = (int) Math.round(attitude[2] * RAD2DEG);     //roll
            }

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

            }
        };
        sensorManager.registerListener(sensorEventListener,
                sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                SensorManager.SENSOR_DELAY_UI);
        sensorManager.registerListener(sensorEventListener,
                sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
                SensorManager.SENSOR_DELAY_UI);

        started = true;
    }

    public static boolean getStarted() {
        return started;
    }

    public static void stop() {
        if(started) {
        sensorManager.unregisterListener(sensorEventListener);
        started = false;
        }
    }
}

最佳答案

老问题,但我在这里回答是为了其他人发现这个问题。

首先,@andrew-morton 链接正是我所需要的,但它是伪代码,所以这里是 Java for Android!

第二:如果可以(您的 API Lvl 最低为 9 或更高),只需使用 Sensor.TYPE_GRAVITY。因为它已经被平滑了。如果您需要支持旧的 API Lvls(就像我必须的那样),这段代码应该可以解决问题!

最后:这段代码 fragment 与我使用它的目的相比有所修改,如果你想自己使用它,你需要为 Vector3 重力创建一个 getter。

注意事项: 我发现 5 (MAX_SAMPLE_SIZE) 的滚动平均值非常平滑。 10 更流畅,但您开始注意到滞后。

import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;  
import java.util.ArrayList;
import java.util.List;

/**
 * Created by andy on 6/14/14.
 */
public class AndroidGravityUpdate implements SensorEventListener {
    private SensorManager sensorManager;
    Vector3 gravity;
    List<Float>[] rollingAverage = new List[3];

    private static final int MAX_SAMPLE_SIZE = 5;

    AndroidGravityUpdate( SensorManager sensorManager ) {
        this.gravity = new Vector3();
        this.sensorManager = sensorManager;

        if(sensorManager.getSensorList(Sensor.TYPE_GRAVITY).size() > 0){
            sensorManager.registerListener(
                    this,
                    sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY),
                    SensorManager.SENSOR_DELAY_GAME
            );
        } else if( sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER).size() > 0) {
            rollingAverage[0] = new ArrayList<Float>();
            rollingAverage[1] = new ArrayList<Float>();
            rollingAverage[2] = new ArrayList<Float>();

            sensorManager.registerListener(
                    this,
                    sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                    SensorManager.SENSOR_DELAY_GAME
                );
        }

    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType()==Sensor.TYPE_GRAVITY){
            gravity.z = event.values[0];
            gravity.x = event.values[1];
            gravity.y = - event.values[2];
        }
        else if ( event.sensor.getType()==Sensor.TYPE_ACCELEROMETER) {
            //For whatever reason, my Samsung only has "Accelerometer"
            // But it is incredibly rough, so attempting to smooth
            // it out with rolling averages.
            rollingAverage[0] = roll(rollingAverage[0], event.values[0]);
            rollingAverage[1] = roll(rollingAverage[1], event.values[1]);
            rollingAverage[2] = roll(rollingAverage[2], -event.values[2]);

            gravity.z = averageList(rollingAverage[0]);
            gravity.x = averageList(rollingAverage[1]);
            gravity.y = averageList(rollingAverage[2]);
        }
    }

    public List<Float> roll(List<Float> list, float newMember){
        if(list.size() == MAX_SAMPLE_SIZE){
            list.remove(0);
        }
        list.add(newMember);
        return list;
    }

    public float averageList(List<Float> tallyUp){

        float total=0;
        for(float item : tallyUp ){
            total+=item;
        }
        total = total/tallyUp.size();

        return total;
    }

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

    }
}

class Vector3 {
    float x;
    float y;
    float z;
}

关于android - 如何以稳定准确的方式读取Android加速度计值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15864223/

有关android - 如何以稳定准确的方式读取Android加速度计值?的更多相关文章

  1. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  2. ruby - 如何以所有可能的方式将字符串拆分为长度最多为 3 的连续子字符串? - 2

    我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123

  3. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  4. Ruby 写入和读取对象到文件 - 2

    好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信

  5. ruby - 无法在 60 秒内获得稳定的 Firefox 连接 (127.0.0.1 :7055) - 2

    我使用的是Firefox版本36.0.1和Selenium-Webdrivergem版本2.45.0。我能够创建Firefox实例,但无法使用脚本继续进行进一步的操作无法在60秒内获得稳定的Firefox连接(127.0.0.1:7055)错误。有人能帮帮我吗? 最佳答案 我遇到了同样的问题。降级到firefoxv33后一切正常。您可以找到旧版本here 关于ruby-无法在60秒内获得稳定的Firefox连接(127.0.0.1:7055),我们在StackOverflow上找到一个类

  6. ruby-on-rails - 正确的 Rails 2.1 做事方式 - 2

    question的一些答案关于redirect_to让我想到了其他一些问题。基本上,我正在使用Rails2.1编写博客应用程序。我一直在尝试自己完成大部分工作(因为我对Rails有所了解),但在需要时会引用Internet上的教程和引用资料。我设法让一个简单的博客正常运行,然后我尝试添加评论。靠我自己,我设法让它进入了可以从script/console添加评论的阶段,但我无法让表单正常工作。我遵循的其中一个教程建议在帖子Controller中创建一个“评论”操作,以添加评论。我的问题是:这是“标准”方式吗?我的另一个问题的答案之一似乎暗示应该有一个CommentsController参

  7. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  8. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  9. python - 如何读取 MIDI 文件、更改其乐器并将其写回? - 2

    我想解析一个已经存在的.mid文件,改变它的乐器,例如从“acousticgrandpiano”到“violin”,然后将它保存回去或作为另一个.mid文件。根据我在文档中看到的内容,该乐器通过program_change或patch_change指令进行了更改,但我找不到任何在已经存在的MIDI文件中执行此操作的库.他们似乎都只支持从头开始创建的MIDI文件。 最佳答案 MIDIpackage会为您完成此操作,但具体方法取决于midi文件的原始内容。一个MIDI文件由一个或多个音轨组成,每个音轨是十六个channel中任何一个上的

  10. STM32读取串口传感器数据(颗粒物传感器,主动上传) - 2

    文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,

随机推荐