Wednesday, June 7, 2017

How to retrieve high quality compass orientation (as in Google Maps)?

Leave a Comment

All of the guides to getting compass orientation in Android I've found have a bug: when you hold the phone in portrait mode and "look" above the horizon, the compass arrow turns 180 degrees from the correct direction.

Google Maps orientation indicator doesn't have this problem.

Another nice thing that Google Maps have is that they somehow estimate compass accuracy. Any idea how they do this?

4 Answers

Answers 1

  1. bug when looking above the horizon.

There is some tricky parts when you work with compass. The compass orientation depends on magnetic fields and phone orientation, so, in order to correct deviation you need to do some matrix operations.

Check this article, it provides a simple example -> https://www.journal.deviantdev.com/android-compass-azimuth-calculating/

Paraphrasing the article: "So if the device is not holding flat (∓45° deviation) you have to use remapCoordinateSystem() in a useful way to get correct results."

  1. accuracy.

First of all, accuracy rely on physical components present in the device. Fragmentation is a common problem here. Samsung magnetometers are different from LG's, and Android System is not going to abstract you from this.

On the other hand, devices could rely on different type of sensors: harward or sensor fusion. So you're going to experiment differences between one device and other.

So this is a mess. But it exists some techniques you could apply in order to get accuracy and uniformed data from sensors (not only for compass, probably GPS too).

  1. Some people discard the first few seconds of sensor data. Some time is needed in order to calibrate the signal, so the first data retrieved use to have some deviation. The time you need to discard depends on manufacturer again, buy I'd try with 5 seconds or so.

  2. Use Interpolators and Extrapolators. Many sensors in android provide you a way to retrieve data each certain milliseconds. But this is the abstraction provided by Android. Harward sensors have its own timing and they update the signal when they they think it is necessary. The rest of the time, when Android ask the sensor for signal data the sensor returns the last value or maybe some kind of operation of the last signal data provided by manufacturer (again).

So, it is interesting to have some abstraction layer (interpolator / extrapolator) which receive the data from Android system each 20, 50, 1000... This layer make some operations in order to have some uniformity, and then communicates the data to your app.

The operation here could be some kind of average between current and last value, accumulated average or maybe another kind of normalization.

Answers 2

I get this error too but not only when you look above the horizon. It's caused because of Euler angles or called Gimbal Lock.

However, compasses(3D compasses, normal compasses does not give correct results due to they are only mapped in x,y and occurs Gimbal Lock) i've seen on Play Store and every code here has a diffence when you keep your device laying flat or screen pointing at you. That difference sometimes gets up to 10 degrees. For 180 degree diffence, you should check if your device is flat or not checking inclination. If it's not flat(AR application) remap coordinate system from x,y to x,z. That will solve the issue but there still be diffence for 2 positions.

SensorManager.getRotationMatrixFromVector(rotationMatrix, event.values); SensorManager.remapCoordinateSystem(rotationMatrix, SensorManager.AXIS_X, SensorManager.AXIS_Z, remappedRM); SensorManager.getOrientation(remappedRM, orientation); 

You can check this project. It's a fine implemetation of 3D compass gives close results for both flat and standing position.

Google measures azimuth from your location. There is a code to find bearing.

currentLocation.getBearing(); 

Accuracy of lat long(accuracy of your current location) is what determines accuracy of bearing.

Answers 3

Compasses will give you what you want, but it's so noisy. It is noisy for 2 reasons, one of reason is, it is picking up, real noise, real signal. So, we live in an environment that's magnetically very noisy. So, this compasses, picking up everything that's magnetic. The other reason is that, it's not integrated, so it doesn't have benefit of dropping the frequency component. So, try to combine your compass with gyroscope data. This video will help you so much for using these sensors.

Some more details, you can combine accelerometers also. So in summary, Gyroscopes provide orientation, Accelerometers provide a correction due to gravity, and compasses provide a correction due to magnetic North.

Answers 4

OK, i figured it out myself. first you need to calculate the bearing from the compass. then the Maps api-2 camera can be rotated.

public void updateCamera(float bearing) {             CameraPosition currentPlace = new CameraPosition.Builder()                     .target(new LatLng(centerLatitude, centerLongitude))                     .bearing(bearing).tilt(65.5f).zoom(18f).build();             googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(currentPlace));      } 

set SensorListener in your code and call this method in onSensorChanged event. i have added a tilt value so the map will rotate in 3D.

[Reference:] [Android Maps v2 rotate mapView with compass1

if you can know about more details http://www.techotopia.com/index.php/Working_with_the_Google_Maps_Android_API_in_Android_Studio

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment