[英]simple Compass using Magnetometer - Android (Java)
I am using Sensortag CC2541 (connected to Nexus phone) 我正在使用Sensortag CC2541 (已连接Nexus手机)
I am using the Magnetometer of this sensor to make a simple compass. 我正在使用此传感器的磁力计制作一个简单的指南针。 I am using the following equations to find North, South, West, and East.
我正在使用以下方程式找到北,南,西和东。
Direction (y>0) = 90 - [arcTAN(x/y)]*180/pi
Direction (y<0) = 270 - [arcTAN(x/y)]*180/pi
Direction (y=0, x<0) = 180.0
Direction (y=0, x>0) = 0.0
Here's the code i'm using in my updateMagnetometer method 这是我在updateMagnetometer方法中使用的代码
@Override
public void onUpdateMagnetometer(SensorTagManager mgr, Point3D b) {
super.onUpdateMagnetometer(mgr, b);
double m=0;
if(b.x < 0.0 && (b.y < 0.01 && b.y > 0.0))
m = 180;
else if(b.x > 0.0 && (b.y < 0.01 && b.y > 0.0))
m = 0;
else if(b.y > 0.0)
m = 90 - (Math.atan(b.x/b.y))*(180/Math.PI);
else if(b.y < 0.0)
m = 270 - (Math.atan(b.x/b.y))*(180/Math.PI);
final float rot = (float) m;
runOnUiThread(new Runnable() {
@Override
public void run() {
pointer.setRotation(-rot); //pointer is the image of my compass
}
});
}
But when I run it, the compass is always stuck between North and West NO MATTER how much I move, rotate, or change the position of the sensor. 但是,当我运行它时,指南针始终固定在“北和西”之间,无论我移动,旋转或更改传感器的位置有多少。
Any mistakes I might be doing? 我可能会犯任何错误?
And also, I have looked a lot on the internet for making compass help. 而且,我在互联网上寻找了很多指南针帮助。 But I can't find anything.
但是我什么也找不到。 Any coding tips, pseudo code, or hint to make compass using magnetometer, accelerometer, and/or gyroscope???
使用磁强计,加速度计和/或陀螺仪制作罗盘的任何编码技巧,伪代码或提示???
Extra info 额外信息
So this is in my main class. 这是我的主要课程。 These methods are called every
x
seconds to update the readings. 每
x
秒调用一次这些方法以更新读数。 PS: my sensor has 2 buttons (right and left) PS:我的传感器有2个按钮(左右)
mStManager.enableSensor(Sensor.MAGNETOMETER,MAGNETOMETER_UPDATE_PERIOD);
mStManager.enableSensor(Sensor.ACCELEROMETER,MAGNETOMETER_UPDATE_PERIOD);
@Override
public void onUpdateAmbientTemperature(SensorTagManager mgr, double temp) {
super.onUpdateAmbientTemperature(mgr, temp);
}
@Override
public void onUpdateAccelerometer(SensorTagManager mgr, Point3D acc) {
super.onUpdateAccelerometer(mgr, acc);
}
@Override
public void onUpdateBarometer(SensorTagManager mgr, double pressure, double height) {
super.onUpdateBarometer(mgr, pressure, height);
}
@Override
public void onUpdateGyroscope(SensorTagManager mgr, Point3D ang) {
super.onUpdateGyroscope(mgr, ang);
}
@Override
public void onUpdateHumidity(SensorTagManager mgr, double rh) {
super.onUpdateHumidity(mgr, rh);
}
@Override
public void onUpdateInfraredTemperature(SensorTagManager mgr, double temp) {
super.onUpdateInfraredTemperature(mgr, temp);
}
@Override
public void onUpdateKeys(SensorTagManager mgr, boolean left, boolean right) {
super.onUpdateKeys(mgr, left, right);
if (right) {
mgr.calibrateMagnetometer();
}
}
@Override
public void onUpdateMagnetometer(SensorTagManager mgr, Point3D b) {
super.onUpdateMagnetometer(mgr, b);
}
}
So basically in the onUpdateMagnetometer
method, the b
contains my reading. 因此,基本上在
onUpdateMagnetometer
方法中, b
包含我的读数。 It is of class Point3D
which is shown below 它是
Point3D
类,如下所示
public class Point3D {
public double x, y, z;
public Point3D(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
public double norm() {
return Math.sqrt(x*x + y*y + z*z);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
long temp;
temp = Double.doubleToLongBits(x);
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(y);
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(z);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Point3D other = (Point3D) obj;
if (Double.doubleToLongBits(x) != Double.doubleToLongBits(other.x))
return false;
if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y))
return false;
if (Double.doubleToLongBits(z) != Double.doubleToLongBits(other.z))
return false;
return true;
}
public String toString() {
return "[" + this.x + ", " + this.y + ", " + this.z + "]";
}
}
One problem you have is that you're handling the 3D magnetometer as a 2D sensor. 您遇到的一个问题是将3D磁力计当作2D传感器使用。 It isn't.
不是。
One way to do this is to use data from both the magnetometer AND the accelerometer: 一种方法是同时使用磁力计和加速度计的数据:
That final value represents the device's rotation around a vector pointed towards the center of the earth, which is exactly what you want for a compass. 最终值表示设备围绕指向地球中心的向量的旋转,这正是您想要的指南针。 Using THAT value, you can then calculate the location of west, east, and south.
然后使用THAT值计算西,东和南的位置。
The code would look something like this: (ignoring the setup of the sensors) 代码看起来像这样:(忽略传感器的设置)
// globals
private float[] gravityData = new float[3];
private float[] geomagneticData = new float[3];
private boolean hasGravityData = false;
private boolean hasGeomagneticData = false;
private double rotationInDegrees;
@Override
public void onSensorChanged(SensorEvent event) {
switch (event.sensor.getType()){
case Sensor.TYPE_ACCELEROMETER:
System.arraycopy(event.values, 0, gravityData, 0, 3);
hasGravityData = true;
break;
case Sensor.TYPE_MAGNETIC_FIELD:
System.arraycopy(event.values, 0, geomagneticData, 0, 3);
hasGeomagneticData = true;
break;
default:
return;
}
if (hasGravityData && hasGeomagneticData) {
float identityMatrix[] = new float[9];
float rotationMatrix[] = new float[9];
boolean success = SensorManager.getRotationMatrix(rotationMatrix, identityMatrix,
gravityData, geomagneticData);
if (success) {
float orientationMatrix[] = new float[3];
SensorManager.getOrientation(rotationMatrix, orientationMatrix);
float rotationInRadians = orientationMatrix[0];
rotationInDegrees = Math.toDegrees(rotationInRadians);
// do something with the rotation in degrees
}
}
}
I hope that helps! 希望对您有所帮助!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.