Question

Possible duplicate : Android getOrientation Azimuth gets polluted when phone is tilted


I am new to android development and I try to get the user facing.

After searching on the web I am pretty sure I need to use remapCoordinateSystem, android documentation say it is good to use for an augmented reality app.

I try to use some existing code to be sure that is a good way.

(Finally I want to create an augmented reality application)

The following code should return the user facing in degree :

Code :

        Sensor sensor = event.sensor;
        if (sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
            gravity = event.values.clone();
        }else if (sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
            geomagnetic = event.values.clone();
        }
        
        if (gravity != null && geomagnetic != null){
            _rM = SensorManager.getRotationMatrix (R, null, gravity, geomagnetic);  
                if(_rM){
                    
                    int mScreenRotation = activity.getWindowManager().getDefaultDisplay().getRotation(); // get user orientation mode
                    switch (mScreenRotation) { // Handle device rotation (landscape, portrait)
                        case Surface.ROTATION_0:
                            axisX = SensorManager.AXIS_X;
                            axisY = SensorManager.AXIS_Y;
                            break;
    
                        case Surface.ROTATION_90:
                            axisX = SensorManager.AXIS_Y;
                            axisY = SensorManager.AXIS_MINUS_X;
                            break;
    
                        case Surface.ROTATION_180: // not handled by my phone so I can't test
                            axisX = SensorManager.AXIS_MINUS_X;
                            axisY = SensorManager.AXIS_MINUS_Y;
                            break;
    
                        case Surface.ROTATION_270:
                            axisX = SensorManager.AXIS_MINUS_Y;
                            axisY = SensorManager.AXIS_X;
                            break;
    
                        default:
                            break;
                    }
                    SensorManager.remapCoordinateSystem (R, axisX, axisY, outR);
                    SensorManager.getOrientation (outR, gO);
            }
        }
        
        
        userFacing = (float) Math.toDegrees(gO[0]); // Radian to degree
        if(userFacing<0) { userFacing+=360; } // -180;180 to 0;360
        return userFacing;

Actually I am able to get an accurate compass when the phone is facing down, but when I try to move the phone (as a user would do), the results are very inaccurate : when i tilt the device, direction can move of 40°...

I saw this link : https://stackoverflow.com/questions/17979238/android-getorientation-azimuth-gets-polluted-when-phone-is-tilted

But if i stay tilted, the results are inaccurate again (it's an average, so it's normal!) And i need the compass working anytime...

I think I will use TYPE_GYROSCOPE, but not all devices have a gyroscope nowadays so i need another solution for all the other devices !

Hope you can understand my problem, and sorry for my bad english! (I'm French)


Solution

Ok so after adapting the application on iOS, I decided to check if the android methods were as good as I though. A month ago, I posted a solution and it was really wrong. I made a huge mistake on remapCoordinateSystem : I used AXIS_X and AXIS_Y to get my matrice and I tried to correct my values with different values. As @HoanNguyen suggested, we just have to use AXIS_X and AXIS_Zand android handle the rest.

So here is the final code. Lot more shorter and easier:

    if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
        gravity = lowPass(event.values.clone(), gravity);
    }
    else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
        geomagnetic = lowPass(event.values.clone(), geomagnetic);
    }
    
    if (geomagnetic != null && gravity != null) {
        if (SensorManager.getRotationMatrix (R_in, null, gravity, geomagnetic)) {               
            SensorManager.remapCoordinateSystem (R_in, SensorManager.AXIS_X, SensorManager.AXIS_Z, R_out);
            SensorManager.getOrientation (R_out, gO);
        }
    }

And to get magnetic north, you just have to use gO[0] like heading = gO[0]; (Caution, the returned values are in radians)

Hope it could here someone!

Était-ce utile?

La solution

Both your code and the solution you found are wrong if by "phone facing" you means the opposite direction of the device z-coordinate. For augmented reality, you just call

remapCoordinateSystem(inR, AXIS_X, AXIS_Z, outR);

independent of the device orientation. Then the azimuth in the call to getOrientation() gives the direction of the phone facing with respect to Magnetic North.

These 2 calls amount to projection of the device z-coordinate to the XY plane of the world coordinates and then calculate the direction of the resulting vector.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top