Fast and simple. How to get the quaternion data from the sensors?
basically I need:
float quaternion_x = ?
float quaternion_y = ?
float quaternion_z = ?
float quaternion_w = ?
I have something like this:
if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR)
{
float[] values = event.values;
float quaternion_x = values[0];
float quaternion_y = values[1];
float quaternion_z = values[2];
float quaternion_w = values[3]; <----- ERROR HERE
}
I get an index out of bound exception because values has only 3 values inside. According to this page:
http://developer.android.com/guide/topics/sensors/sensors_motion.html
There should be 4 values or am I understanding something wrong?
The SensorManager class offers a helper function to convert for you:
SensorManager.getQuaternionFromVector(Q, values);
float[] quaternion_w = Q[0];
float[] quaternion_x = Q[1];
float[] quaternion_y = Q[2];
float[] quaternion_z = Q[3];
The android implementation of getOrientation returns the same values of getQuaterionFromVector.
So, you can take those values and construct the Quaternion if you want;
float[] quaternion = new float[4];
quaternion[0] = 0; //w
quaternion[1] = orientation[0]; //x
quaternion[2] = orientation[1]; //y
quaternion[3] = orientation[2]; //z
I checked it out with this code.
#Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
mMagneticField = event.values;
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
mGravity = event.values;
if ((mGravity == null) || (mMagneticField == null))
return;
float R[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I, mGravity, mMagneticField);
if (success) {
mOrientation = new float[3];
mQuaternion = new float[4];
SensorManager.getOrientation(R, mOrientation);
mAzimut = mOrientation[0]; // orientation contains: azimut, pitch and roll
mPitch = mOrientation[1];
mRoll = mOrientation[2];
SensorManager.getQuaternionFromVector(mQuaternion, mOrientation);
if(mAzimut - mQuaternion[1] == 0 && mPitch - mQuaternion[2] == 0 && mRoll - mQuaternion[3] == 0){
Log.d("ORIENTATION", "QUATERNION IS THE SAME");
}
notifyObservers();
}
}
Related
This is my code so far and is changing the rotation of the marker regarding the position of the tablet.
float[] mGravity;
float[] mGeomagnetic;
Float azimut;
Marker Mymarker;
MarkerOptions MyMarkerOption = new MarkerOptions();
public void onSensorChanged(SensorEvent event) {
if(GotLocation){
if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
mGravity = event.values;
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
mGeomagnetic = event.values;
if (mGravity != null && mGeomagnetic != null) {
float R[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I, mGravity, mGeomagnetic);
MyLocation = new LatLng(currentLatitude, currentLongitude);
if (success) {
float orientation[] = new float[3];
SensorManager.getOrientation(R, orientation);
azimut = orientation[0];
float azimuthInRadians = orientation[0];
float azimuthInDegress = (float)(Math.toDegrees(azimuthInRadians)+360)%360;
if(location_marker == 0){
MyMarkerOption.position(MyLocation);
Mymarker = map.addMarker(MyMarkerOption);
location_marker++;
}
Mymarker.setPosition(MyLocation);
Mymarker.setRotation(azimuthInDegress);
Mymarker.setFlat(true);
}
}
}
}
I would like that the rotation of the marker changes regarding a given lat-long position. So I guess that now the algorithm is calculating the azimuthInDegress regarding the tablet. I would like that it calculates it regarding a given point.
I found this thread where someone was asking the same thing, but I do not know how to implement this solution for my code..The thread is also 5 years old so maybe there is another solution right now.
Which is the inclination of the moving angle to an angle 0 which corresponds to mobile laid flat.
I want exactly measure angle on the corner walls (between 2 walls)
I already use this code, and the results obtained:
public void onAccuracyChanged(Sensor sensor, int accuracy) {
float[] mGravity;
float[] mGeomagnetic;
public void onSensorChanged(SensorEvent event){
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
mGravity = event.values.clone();
}
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
mGeomagnetic = event.values.clone();
if (mGravity != null && mGeomagnetic != null) {
float R[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I, mGravity, mGeomagnetic);
if (success) {
float orientation[] = new float[3];
SensorManager.getOrientation(R, orientation);
azimut = orientation[0];
mAzimuthView.setText(String.format("%.2f",Math.toDegrees(azimut)) + '°');
tv.setText(String.format("%.2f", Math.toDegrees(azimut-angle_reset)) + '°');
}
}
}
1 - GSM is a flat vertical -> azimuth = 37 ° .
2 - Turn GSM Horizontally 90 ° -> = -111 ° azimuth .
So the difference ( 111-37 ) is 74 ° !!!! ( But normally I have to get 90 °)
i cant solve the problem of titlename.
like you see in the following sourcecode, ive already tried to add 360 on
my result if the sign is negtive. but it seems it didnt work a well.
OnSensorChanged()
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
mAccelerometer = event.values;
}
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
mGeomagnetic = event.values;
}
if (mAccelerometer != null && mGeomagnetic != null) {
float R[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I,
mAccelerometer, mGeomagnetic);
if (success) {
float orientation[] = new float[3];
SensorManager.getOrientation(R, orientation);
// An dieser Stelle enthält das Array orientation[] die Werte für azimuth, pitch und roll.
double tempAzimuth = 180 * orientation[0] / Math.PI;
if(tempAzimuth < 0){
swAzimuth = tempAzimuth + 360;
}
else{
swAzimuth = tempAzimuth;
}
//
//double pitch = 180 * orientation[1] / Math.PI;
//double roll = 180 * orientation[2] / Math.PI;
txt.setText(String.valueOf(swAzimuth));
Log.d("direction", String.valueOf(swAzimuth));
}
}
}
I want to compute the compass' direction, so I use the following code:
SensorManager mManager = (SensorManager)mContext.getSystemService(Context.SENSOR_SERVICE);
Sensor accelerometer = mManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
Sensor magnetometer = mManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
mManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL);
mManager.registerListener(this, magnetometer, SensorManager.SENSOR_DELAY_NORMAL);
private float mR[] = new float[9];
private float mI[] = new float[9];
float mOrientation[] = new float[3];
....
public void onSensorChanged(SensorEvent event)
{
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
mGravity = event.values;
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
mGeomagnetic = event.values;
if (mGravity != null && mGeomagnetic != null) {
boolean success = SensorManager.getRotationMatrix(mR, mI, mGravity, mGeomagnetic);
if (success) {
SensorManager.getOrientation(mR, mOrientation);
int azimut = (int) (mOrientation[0]*180/3.14159f); // This is the data
}
}
}
It usually works fine. It does not work when there is an interference with the magnetic field - for example under my car radio. In that case - I get a wrong constant reading.
how can I detect magnetic interference?
I am trying to get the compass bearing in degrees (i.e. 0-360) using the following method:
float[] mGravity;
float[] mGeomagnetic;
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
mGravity = event.values;
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
mGeomagnetic = event.values;
if (mGravity != null && mGeomagnetic != null) {
float R[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I, mGravity,
mGeomagnetic);
if (success) {
float orientation[] = new float[3];
SensorManager.getOrientation(R, orientation);
float azimut = orientation[0];
bearing.setText("Bearing: "+ azimut);
}
}
}
The azimuth value (i.e. orientation[0]) should be 0<=azimuth<360 but I am getting only values from -3 to 3 as I rotate my device. Can someone please tell me what the problem might be please?
The values are in radian, you have to convert to degree of arc
int azimut = (int) Math.round(Math.toDegrees(orientation[0]));
It is true that it is in Radians. Thanks Hoan. I added some logic to get that bearing in degrees from 0 to 360 becuase if I only converted it to degrees, I was getting values from -180 to 180.
float azimuthInRadians = orientation[0];
float azimuthInDegress = (float)Math.toDegrees(azimuthInRadians)+360)%360;
// This answer applies to Google Maps api v2.
// It is possible by registering your application with Sensor Listener for Orientation and get the
// angle relative to true north inside onSensorChanged and update camera accordingly.
// Angle can be used for bearing. Following code can be used:
// Instead of using Sensor.TYPE_ORIENTATION try using getOrinetation api. Sensor.TYPE_ORIENTATION
// has been deprecated.
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
if (sensorManager != null)
sensorManager.registerListener(this,
sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
SensorManager.SENSOR_DELAY_GAME);
}
public void onSensorChanged(SensorEvent event) {
float compassBearingRelativeToTrueNorth = Math.round(event.values[0]);
Log.d(TAG, "Degree ---------- " + degree);
updateCamera(compassBearingRelativeToTrueNorth);
}
private void updateCamera(float bearing) {
CameraPosition oldPos = googleMap.getCameraPosition();
CameraPosition pos = CameraPosition.builder(oldPos).bearing(bearing)
.build();
googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(pos));
}