您当前的位置: 首页 > 学无止境 > 心得笔记 网站首页心得笔记
88_采用传感器获取手机的方向-指南针的精准度
发布时间:2021-03-28 18:19:55编辑:雪饮阅读()
其实在上次完善了指南针程序后基本上就算是完事了,但是呢其实对于使用Sensor.TYPE_ORIENTATION注册监听方向监听来说其实这个在官方文档里面从api15就废弃了,虽然还能用就是,但是新的api据说是可以获取到更精准的数据
![指南针.png](/d/file/xuewuzhijing/xindebiji/9893ba5b5b92099f060da8b52d68f8dc.png)
android给我们提供的方向数据是一个float型的数组,包含三个方向的值 如图
![指南针.png](/d/file/xuewuzhijing/xindebiji/6ec02f83c2d1a0d56adbd729515b97cf.png)
那么这里就对接下官方的这个推荐接口来实现下指南针逻辑,那么其它都不动,还是只修改下逻辑层,则如MainActivity.java:
package com.example.pointer;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.Log;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private ImageView iv;
TextView tv;
float predegree = 0;
private SensorManager sm;
//需要两个Sensor
private Sensor aSensor;
private Sensor mSensor;
float[] accelerometerValues=new float[3];
float[] magneticFieldValues=new float[3];
private static final String TAG="sensor";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) this.findViewById(R.id.textView);
iv = (ImageView) this.findViewById(R.id.iv);
}
@Override
//Activity第一次创建时或重新加载实例时调用
protected void onResume() {
sm=(SensorManager)getSystemService(Context.SENSOR_SERVICE);
//加速度传感器
aSensor=sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
//地磁传感器
mSensor=sm.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
sm.registerListener(myListener,aSensor,SensorManager.SENSOR_DELAY_GAME);
sm.registerListener(myListener,mSensor,SensorManager.SENSOR_DELAY_GAME);
//更新显示数据的方法
calculateOrientation();
super.onResume();
}
@Override
protected void onPause() {
sm.unregisterListener(myListener);// 注消传感器监听
super.onPause();
}
final SensorEventListener myListener = new SensorEventListener() {
public void onSensorChanged(SensorEvent sensorEvent){
if(sensorEvent.sensor.getType()==Sensor.TYPE_MAGNETIC_FIELD) {magneticFieldValues=sensorEvent.values;}
if(sensorEvent.sensor.getType()==Sensor.TYPE_ACCELEROMETER){
accelerometerValues=sensorEvent.values;
}
calculateOrientation();
}
public void onAccuracyChanged(Sensor sensor,int accuracy){}
};
private void calculateOrientation() {
float[] values=new float[3];
float[] R = new float[9];
SensorManager.getRotationMatrix(R,null,accelerometerValues,magneticFieldValues);
SensorManager.getOrientation(R,values);
// 要经过一次数据格式的转换,转换为度
values[0]=(float) Math.toDegrees(values[0]);
Log.i(TAG,values[0]+"");
if(values[0] >= -5 && values[0] < 5){
Log.i(TAG,"正北");
}
else if(values[0] >=5 && values[0] < 85){
Log.i(TAG,"东北");
}else if(values[0] >= 85 && values[0] <=95){
Log.i(TAG, "正东");
}else if(values[0] >=95 && values[0] <175){
Log.i(TAG,"东南");
}else if((values[0]>=175 && values[0]<=180)||(values[0]) >= -180 && values[0] < -175){
Log.i(TAG,"正南");
}
else if(values[0] >=-175 && values[0] <-95){
Log.i(TAG,"西南");
}
else if(values[0] >= -95 && values[0] < -85){
Log.i(TAG,"正西");}
else if(values[0] >= -85 && values[0] < -5){
Log.i(TAG,"西北");
}
/*
* values[0]:
表示Z轴的角度:方向角,我们平时判断的东西南北就是看这个数据的,经过我的实验,发现了一个有意思的事情.
也就是说使用第一种方式获得方向(磁场+加速度)得到的数据范围是(-180~180),也就是说,0表示正北,90表示正东,180/-180表示正南,-90表示正西。
而第二种方式(直接通过方向感应器)数据范围是(0~360)360/0表示正北,90表示正东,180表示正南,270表示正西。
values[1]:表示X轴的角度:俯仰角 即由静止状态开始,前后翻转
values[2]:表示Y轴的角度:翻转角 即由静止状态开始,左右翻转
* */
String orientationSensorLog="Orientation Sensor: " + values[0] + ", " + values[1] + ", "+ values[2];
tv.setText(orientationSensorLog);
System.out.println(orientationSensorLog);
float xoz=values[0];
RotateAnimation ra = new RotateAnimation(predegree, -xoz, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
ra.setDuration(500);
ra.setFillAfter(true);
iv.startAnimation(ra);
predegree =xoz;
}
}
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.Log;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private ImageView iv;
TextView tv;
float predegree = 0;
private SensorManager sm;
//需要两个Sensor
private Sensor aSensor;
private Sensor mSensor;
float[] accelerometerValues=new float[3];
float[] magneticFieldValues=new float[3];
private static final String TAG="sensor";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) this.findViewById(R.id.textView);
iv = (ImageView) this.findViewById(R.id.iv);
}
@Override
//Activity第一次创建时或重新加载实例时调用
protected void onResume() {
sm=(SensorManager)getSystemService(Context.SENSOR_SERVICE);
//加速度传感器
aSensor=sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
//地磁传感器
mSensor=sm.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
sm.registerListener(myListener,aSensor,SensorManager.SENSOR_DELAY_GAME);
sm.registerListener(myListener,mSensor,SensorManager.SENSOR_DELAY_GAME);
//更新显示数据的方法
calculateOrientation();
super.onResume();
}
@Override
protected void onPause() {
sm.unregisterListener(myListener);// 注消传感器监听
super.onPause();
}
final SensorEventListener myListener = new SensorEventListener() {
public void onSensorChanged(SensorEvent sensorEvent){
if(sensorEvent.sensor.getType()==Sensor.TYPE_MAGNETIC_FIELD) {magneticFieldValues=sensorEvent.values;}
if(sensorEvent.sensor.getType()==Sensor.TYPE_ACCELEROMETER){
accelerometerValues=sensorEvent.values;
}
calculateOrientation();
}
public void onAccuracyChanged(Sensor sensor,int accuracy){}
};
private void calculateOrientation() {
float[] values=new float[3];
float[] R = new float[9];
SensorManager.getRotationMatrix(R,null,accelerometerValues,magneticFieldValues);
SensorManager.getOrientation(R,values);
// 要经过一次数据格式的转换,转换为度
values[0]=(float) Math.toDegrees(values[0]);
Log.i(TAG,values[0]+"");
if(values[0] >= -5 && values[0] < 5){
Log.i(TAG,"正北");
}
else if(values[0] >=5 && values[0] < 85){
Log.i(TAG,"东北");
}else if(values[0] >= 85 && values[0] <=95){
Log.i(TAG, "正东");
}else if(values[0] >=95 && values[0] <175){
Log.i(TAG,"东南");
}else if((values[0]>=175 && values[0]<=180)||(values[0]) >= -180 && values[0] < -175){
Log.i(TAG,"正南");
}
else if(values[0] >=-175 && values[0] <-95){
Log.i(TAG,"西南");
}
else if(values[0] >= -95 && values[0] < -85){
Log.i(TAG,"正西");}
else if(values[0] >= -85 && values[0] < -5){
Log.i(TAG,"西北");
}
/*
* values[0]:
表示Z轴的角度:方向角,我们平时判断的东西南北就是看这个数据的,经过我的实验,发现了一个有意思的事情.
也就是说使用第一种方式获得方向(磁场+加速度)得到的数据范围是(-180~180),也就是说,0表示正北,90表示正东,180/-180表示正南,-90表示正西。
而第二种方式(直接通过方向感应器)数据范围是(0~360)360/0表示正北,90表示正东,180表示正南,270表示正西。
values[1]:表示X轴的角度:俯仰角 即由静止状态开始,前后翻转
values[2]:表示Y轴的角度:翻转角 即由静止状态开始,左右翻转
* */
String orientationSensorLog="Orientation Sensor: " + values[0] + ", " + values[1] + ", "+ values[2];
tv.setText(orientationSensorLog);
System.out.println(orientationSensorLog);
float xoz=values[0];
RotateAnimation ra = new RotateAnimation(predegree, -xoz, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
ra.setDuration(500);
ra.setFillAfter(true);
iv.startAnimation(ra);
predegree =xoz;
}
}
然后实现的效果如
![指南针.png](/d/file/xuewuzhijing/xindebiji/c005855949c1880b37782bd6b66a76da.png)
随后进行和内置的一些指南针应用来对比的时候,发现咱们这个会出现方向是反的,但是其实吧,我感觉这个主要是因为一些内置的指南针应用都有一个校准的过程,指南针应该和百度地图、谷歌地图等差不多,都会有偏差。但是完全相反,这个偏差就有点大,所以还怀疑应该是因为我们的应用没有以正式版而是以开发版安装的,查看了一些资料,好像是说开发版和正式版有相反的问题。
关键字词:传感器,指南针,android
下一篇:89_如何安全的退出应用程序