Android手机中获取角度摇控小车(1)

为了让小车的摇控器更好用的一点,学习了在手机上通过手机自身的加速传感器和磁力传感器来获取角度等参数。今天是学习python的第十九天,今天的内容和python没有什么关系。

受玩手机上飞车的影响,感觉用手机做一个小车的摇控器会比在网页上点点体验好一些,通过转动手机来控制小车的方向,通过上下翻转来控制前进和后退。 思路有了,那就开始动工了。

打开Android studio,创建一个空白项目,叫rpicar,下一步下一步完成之后 开始编写代码,今天主要用到了二个传感器来获取方向,上下倾斜角.

获取传感器,看机器是否支持

mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);  
        List<Sensor> deviceSensors = mSensorManager.getSensorList(Sensor.TYPE_ALL);
        for (Sensor s : deviceSensors) {
            Log.d(tag, s.getType() + ":" + s.getName());
        }

红米Note3的

02-01 22:13:14.089 9209-9209/com.witleaf.rpicar D/rpicar: 1:LSM6DS3 Accelerometer  
02-01 22:13:14.089 9209-9209/com.witleaf.rpicar D/rpicar: 2:YAS537 Magnetometer  
02-01 22:13:14.089 9209-9209/com.witleaf.rpicar D/rpicar: 14:YAS537 Magnetometer Uncalibrated  
02-01 22:13:14.089 9209-9209/com.witleaf.rpicar D/rpicar: 4:LSM6DS3 Gyroscope  
02-01 22:13:14.090 9209-9209/com.witleaf.rpicar D/rpicar: 16:LSM6DS3 Gyroscope Uncalibrated  
02-01 22:13:14.090 9209-9209/com.witleaf.rpicar D/rpicar: 8:stk3x1x alsprx  
02-01 22:13:14.090 9209-9209/com.witleaf.rpicar D/rpicar: 5:stk3x1x alsprx  
02-01 22:13:14.090 9209-9209/com.witleaf.rpicar D/rpicar: 2:YAS537 Magnetometer -Wakeup Secondary  
02-01 22:13:14.090 9209-9209/com.witleaf.rpicar D/rpicar: 14:YAS537 Magnetometer Uncalibrated -Wakeup Secondary  
02-01 22:13:14.090 9209-9209/com.witleaf.rpicar D/rpicar: 16:LSM6DS3 Gyroscope Uncalibrated -Wakeup Secondary  
02-01 22:13:14.090 9209-9209/com.witleaf.rpicar D/rpicar: 8:stk3x1x alsprx -Non Wakeup Secondary  
02-01 22:13:14.090 9209-9209/com.witleaf.rpicar D/rpicar: 5:stk3x1x alsprx -Wakeup Secondary  
02-01 22:13:14.090 9209-9209/com.witleaf.rpicar D/rpicar: 9:Gravity  
02-01 22:13:14.090 9209-9209/com.witleaf.rpicar D/rpicar: 10:Linear Acceleration  
02-01 22:13:14.090 9209-9209/com.witleaf.rpicar D/rpicar: 11:Rotation Vector  
02-01 22:13:14.090 9209-9209/com.witleaf.rpicar D/rpicar: 18:Step Detector  
02-01 22:13:14.090 9209-9209/com.witleaf.rpicar D/rpicar: 19:Step Counter  
02-01 22:13:14.090 9209-9209/com.witleaf.rpicar D/rpicar: 17:Significant Motion Detector  
02-01 22:13:14.090 9209-9209/com.witleaf.rpicar D/rpicar: 15:Game Rotation Vector  
02-01 22:13:14.090 9209-9209/com.witleaf.rpicar D/rpicar: 20:GeoMagnetic Rotation Vector  
02-01 22:13:14.090 9209-9209/com.witleaf.rpicar D/rpicar: 3:Orientation  
02-01 22:13:14.090 9209-9209/com.witleaf.rpicar D/rpicar: 22:Tilt Detector  
02-01 22:13:14.090 9209-9209/com.witleaf.rpicar D/rpicar: 9:Gravity -Wakeup Secondary  
02-01 22:13:14.090 9209-9209/com.witleaf.rpicar D/rpicar: 10:Linear Acceleration -Wakeup Secondary  
02-01 22:13:14.090 9209-9209/com.witleaf.rpicar D/rpicar: 11:Rotation Vector -Wakeup Secondary  
02-01 22:13:14.090 9209-9209/com.witleaf.rpicar D/rpicar: 18:Step Detector -Wakeup Secondary  
02-01 22:13:14.090 9209-9209/com.witleaf.rpicar D/rpicar: 19:Step Counter -Wakeup Secondary  
02-01 22:13:14.090 9209-9209/com.witleaf.rpicar D/rpicar: 15:Game Rotation Vector -Wakeup Secondary  
02-01 22:13:14.090 9209-9209/com.witleaf.rpicar D/rpicar: 20:GeoMagnetic Rotation Vector -Wakeup Secondary  

第一行,二行就看到了我们今天要用的二个传感器 加速计Accelerometer 磁力计Magnetometer

先注册这二个传感,然后实现传感觉器的二个事件,具体见代码

package com.witleaf.rpicar;

import android.hardware.Sensor;  
import android.hardware.SensorEvent;  
import android.hardware.SensorEventListener;  
import android.hardware.SensorManager;  
import android.support.v7.app.AppCompatActivity;  
import android.os.Bundle;  
import android.util.Log;

import java.util.List;

public class MainActivity extends AppCompatActivity implements SensorEventListener {

    final String tag = "rpicar";

    private boolean mRegisterSensor;
    private SensorManager mSensorManager;

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

    float[] accelerometerValues = new float[3];
    float[] magneticFieldValues = new float[3];
    float[] values = new float[3];
    float[] rotate = new float[9];

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRegisterSensor = false;
        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        aSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        mSensorManager.registerListener(this, aSensor, SensorManager.SENSOR_DELAY_GAME);
        mSensorManager.registerListener(this, mSensor, SensorManager.SENSOR_DELAY_GAME);
    }


    @Override
    public void onSensorChanged(SensorEvent event) {
        synchronized (this) {
            if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
                accelerometerValues = event.values;
            }
            if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
                magneticFieldValues = event.values;
            }

            boolean flag = SensorManager.getRotationMatrix(rotate, null, 
            accelerometerValues, magneticFieldValues);
            SensorManager.getOrientation(rotate, values);
            values[0] = (float) Math.toDegrees(values[0]);
            values[1] = (float) Math.toDegrees(values[1]);
            values[2] = (float) Math.toDegrees(values[2]);
            Log.d(tag, values[0] + " ," + values[1] + "," + values[2]);
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        Log.d(tag, "onAccuracyChanged: " + sensor + ", accuracy: " + accuracy);
    }

    @Override
    protected void onResume() {
        super.onResume();
        mSensorManager.registerListener(this, aSensor, SensorManager.SENSOR_DELAY_GAME);
        mSensorManager.registerListener(this, mSensor, SensorManager.SENSOR_DELAY_GAME);
    }

    @Override
    protected void onStop() {
        // 取消注册
        mSensorManager.unregisterListener(this);
        super.onStop();
    }
}

运行测试

接上手机开始测试,我们可以看到移动手向方向,值会不停的变动.

总结一下

主要用到了二个方法

  • public static boolean getRotationMatrix (float[] R, float[] I, float[] gravity, float[] geomagnetic)

    • R :调用方法会填充,大小是9
    • I :将磁场数据转换进实际的重力坐标中 默认情况下可以设置为null
    • gravity 是一个大小为3的数组,从加速度感应器获取来的数据
    • geomagnetic 是一个大小为3的数组,从磁场感应器获取来的数据
  • SensorManager.getOrientation(rotate, values);

    • rotate 就是上面的R
    • value 是返回值
values[0]: azimuth, rotation around the Z axis.  
values[1]: pitch, rotation around the X axis.  
values[2]: roll, rotation around the Y axis.  

接下来就要连接小车上的websocket服务,然后计算来控制小车了期待调通的那一时刻。

本文主要参考了以下内容 关于Android 传感器坐标与读数的进一步讨论