Geolocation + Accelerometer = Orientation

In order to get orientation of your android device you need to do “some” math, based on geolocation and accelerometer values. Working with Android native SDK, you are able to get orientation as easy as calling SensorManager.getOrientation(), but when it comes to AIR SDK, you have no access to the native SDK methods. However, thanks to open sources you are able to grab the original source and rewrite the thing into ActionScript. That is exatcly what I have done. The results are GeomagneticField and SensorManager classes. To make this happen you need both AccelerometerEvent and GeolocationEvent values as intput:

import sk.yoz.hardware.GeomagneticField;
import sk.yoz.hardware.SensorManager;

var event1:GeolocationEvent; // real event with correct values
var event2:AccelerometerEvent; // real event with correct values
var R:Array = new Array(9);
var geomagneticField:GeomagneticField = new GeomagneticField(
    event1.latitude, event1.longitude, event1.altitude, new Date().time);
SensorManager.getRotationMatrix(
    event2.accelerationX, event2.accelerationY, event2.accelerationZ,
    geomagneticField.x, geomagneticField.y, geomagneticField.z, R);
var orientation:Array = SensorManager.getOrientation(R);
orientation[0] // orientation X in radians
orientation[1] // orientation Y in radians
orientation[2] // orientation Z in radians

… do not forget to add permissions into manifest file

<uses-permission android:name="android.permission.LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

11 comments so far

  1. zatoitche March 23, 2011 22:25

    Man… that is some neat porting. You have saved me lots of time and hair-pulling. Thank you , thank you, thank you. I would like to take your permission on expanding on this by making examples of my own using your code…. Awaiting your green light.

  2. Jozef Chúťka March 23, 2011 23:10

    zatoitche sure, feel free to use the code, the original java source was released under apache2 license… let me know when examples ready. I would like to see 😉

  3. zatoitche March 24, 2011 20:40

    Hey man, thanks again for the code and the reply. I am working on a couple of nice examples, but I am having some trouble with the output. I am sure you have tested the code, but just to confirm. orientation[0] is the one that has a lot of fluctuations. I tried filtering the data through a moving average filter but with no use (no matter how big the array is). If I understand the mechanics correctly, here is what I am trying to achieve: I need to get the rotation around the Z axis ( which is the axis that connects me to the center of the earth, as per android docs for getOrientation), so if I imagine a vector coming out from the back of my phone and pointing north as I hold it upright,then if I turn the phone so that vector is pointing east I should get an absolute rotation of 90 degrees. Am I right to assume that orientation[0] is what I need? and have you built any app using this code and what did you use to smooth out the data? Mind you, I might have a bad sensor in my phone (Samsung Captivate: Froyo)…. Let me know your thoughts….. thanks in advance man.

  4. Jozef Chúťka March 25, 2011 11:18

    zatoitche, your assumption is wrong. how to start…
    lets think of accelerometer as and empty box containing a little ball in it. based on how you move/rotate the box the ball inside hits the box borders. so when your box sits on one side and you rotate onto another, ball hits different box side and has the info something changes. now imagine you move box the way that it sits on one side and some focused side heads north, you move the box so our side heads south. does our ball inside moved anyhow? no, because it still pushes the same side. here comes compass on the stage. flash uses GeolocationEvent, that in fact combines gps and compass, unfortunately the compass property “heading” is not supported by android devices http://help.adobe.com/en_US/FlashPlatform/beta/reference/actionscript/3/flash/events/GeolocationEvent.html#heading
    because of this, you are currently not able to detect heading of your phone 🙁

    what SensorManager.getOrientation() does is it computes rotation of your phone according to just gravity (no compass), with some small corrections based on geomagnetic field specifics in time and place on earth. you can see some demo here:
    http://remotair.yoz.sk/ first video at 2:20

    while we do not have GeolocationEvent.heading in flash, we will not be able to create applications like android street view is.

  5. zatoitche April 1, 2011 20:14

    Hey Jozef,

    Thanks for the reply. I apologize for misunderstanding. Although when I read the android documentations for “SensorManager.getOrientation()” they described the reference axis with respect to the earth and magnetic north (specifically the y axis). it is a bummer that the Geolocation.heading is not functioning. I have tried to find out resources as to why but could not get further than “android devices do not support it”, which I think is completely nonsense since you can have that property in the native fashion.

    However, I have been messing around with the accelerometer and I am trying something that I would like to run by you:
    – we can confirm that global orientation is not supported (AIR), yet local orientation is.

    – all 3 axis respond to motion with acceleration values.
    – from acceleration and time stamp we can get speed, and from speed we can get distance (Thank you Newton….ah, I mean thank you apple tree 🙂 …)
    -if we can translate this distance to pixel movement then … bingo, we have not created a global orientation, but we expanded on the local one.

    What are your thoughts.

  6. Jozef Chúťka April 4, 2011 10:29

    zatoitche,
    I believe they will make heading working very soon, than we will be able to handle everything correctly. I double checked the docs and I am not sure where the computation occurs – I mean the X,Y,Z rotations based on heading… becaause:

    GeomagneticField – computes the magnetic declination from true north (magnetic declination = angle between magnetic north and true north http://en.wikipedia.org/wiki/Magnetic_declination) based on current location on the earth
    – no heading input into this function

    SensorManager.getOrientation argmunent geomagnetic = 3 floats containing the geomagnetic vector expressed in the device’s coordinate. so still no heading as far as I understand

    do you have any idea? I think I need to take a much deeper look into this


    to your question: yes, based on acceleration and time you should be able to count distance, to transpone the real world distance into pixels you need DPI, checkout http://blog.yoz.sk/2010/12/quick-tip-systemscreen-class/

  7. Jozef Chúťka April 4, 2011 10:31
  8. Pascal April 4, 2012 17:55

    Hi Josef,

    I tried the GeomagneticField class to compute declination and I am getting wrong results:

    For:

    Zip code: 60040
    Lat: 42.205724 (North)
    Long: 87.814216 (West)
    Altitude: 182m

    According to NOAA’s website ( http://www.ngdc.noaa.gov/geomagmodels/struts/calcDeclination ), I should be getting: 3 deg 32′

    According to GeomagneticField( 42.205724, – 87.814216, 182, ( new Date() ).valueOf() ), GeomagneticField.declination –> -166.54 deg

    Huh?

  9. Jozef Chúťka April 5, 2012 08:50

    hi Pascal,
    I took those classes from android sdk at Dec 10, 2010, there is a lot of constants and math I do not even pretend I understand, and I believe are subject of change with later android sdks and time etc. You may have some better results with latest release
    http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.3_r1/android/hardware/GeomagneticField.java#GeomagneticField

  10. Pascal April 5, 2012 10:52

    Hey Jozef,

    Ok. Thank’s for the link.

    I also found this one:

    http://www.ngdc.noaa.gov/geomag/WMM/thirdpartycontributions.shtml

    The Java one might be a good place to start…

    – P.

  11. Jozef Chúťka April 6, 2012 22:35

    … kudos to Pascal for noticing some bugs in GeomagneticField.as, the code has been fixed and should be fine now.

Leave a comment

Please be polite and on topic. Your e-mail will never be published.