Android Sensor Fusion Tutorial

While working on my master thesis, I’ve made some experiences with sensors in Android devices and I thought  I’d share them with other Android developers stumbling over my blog. In my work I was developing a head tracking component for a prototype system. Since it had to adapt audio output to the orientation of the users head, it required to respond quickly and be accurate at the same time.

I used my Samsung Galaxy S2 and decided to use its gyroscope in conjunction with the accelerometer and the magnetic field sensor in order to measure the user’s head rotations both, quickly and accurately. To acheive this I implemented a complementary filter to get rid of the gyro drift and the signal noise of the accelerometer and magnetometer. The following tutorial describes in detail how it’s done.

There are already several tutorials on how to get sensor data from the Android API, so I’ll skip the details on android sensor basics and focus on the sensor fusion algorithm. The Android API Reference is also a very helpful entry point regarding the acquisition of sensor data. This tutorial is based on the Android API version 10 (platform 2.3.3), by the way.

This article is divided into two parts. The first part covers the theoretical background of a complementary filter for sensor signals as described by Shane Colton here. The second part describes the implementation in the Java programming laguage. Everybody who thinks the theory is boring and wants to start programing right away can skip directly to the second part. The first part is interesting for people who develop on other platforms than Android, iOS for example, and want to get better results out of the sensors of their devices.

Update (March 22, 2012):
I’ve created a small Android project which contains the whole runnable code from this tutorial. You can download it here:
SensorFusion1.zip

Update (April 4, 2012):
Added a small bugfix in the examples GUI code.

Update (July 9, 2012):
Added a bugfix regarding angle transitions between 179° <–> -179°. Special thanks to J.W. Alexandar Qiu who pointed it out and published the soultion!

Update (September 25, 2012):
Published the code under the MIT-License (license note added in code), which allows you to do with it pretty much everything you want. No need to ask me first ;)

Sensor Fusion via Complementary Filter

Before we start programming, I want to explain briefly how our sensor fusion approach works. The common way to get the attitude of an Android device is to use the SensorManager.getOrientation() method to get the three orientation angles. These two angles are based on the accelerometer and magenotmeter output. In simple terms, the acceletometer provides the gravitiy vector (the vector pointing towards the centre of the earth) and the magnetometer works as a compass. The Information from both sensors suffice to calculate the device’s orientation. However both sensor outputs are inacurate, expecially the output from the magnetic field sensor which includes a lot of noise.

The gyroscope in the device is far more accurate and has a very short response time. Its downside is the dreaded gyro drift. The gyro provides the angular rotation speeds for all three axes. To get the actual orientation those speed values need to be integrated over time.  This is done by multiplying the angular speeds with the time interval between the last and the current sensor output. This yields a rotation increment. The sum of all rotation increments yields the absolut orientation of the device. During this process small errors are introduced in each iteration. These small errors add up over time resulting in a constant slow rotation of the calculated orientation, the gyro drift.

To avoid both, gyro drift and noisy orientation, the gyroscope output is applied only for orientation changes in short time intervals, while the magnetometer/acceletometer data is used as support information over long periods of time. This is equivalent to low-pass filtering of the accelerometer and magnetic field sensor signals and high-pass filtering of the gyroscope signals. The overall sensor fusion and filtering looks like this:

So what exactly does high-pass and low-pass filtering of the sensor data mean? The sensors provide their data at (more or less) regular time intervals. Their values can be shown as signals in a graph with the time as the x-axis, similar to an audio signal. The low-pass filtering of the noisy accelerometer/magnetometer signal (accMagOrientation in the above figure) are orientation angles averaged over time within a constant time window.

Later in the implementation, this is accomplished by slowly introducing new values from the accelerometer/magnetometer to the absolute orientation:

// low-pass filtering: every time a new sensor value is available
// it is weighted with a factor and added to the absolute orientation
accMagOrientation = (1 - factor) * accMagOrientation + factor * newAccMagValue;

The high-pass filtering of the integrated gyroscope data is done by replacing the filtered high-frequency component from accMagOrientation with the corresponding gyroscope orientation values:

fusedOrientation =
    (1 - factor) * newGyroValue;    // high-frequency component
    + factor * newAccMagValue;      // low-frequency component

In fact, this is already our finished comlementary filter.

Assuming that the device is turned 90° in one direction and after a short time turned back to its initial position, the intermediate signals in the filtering process would look something like this:

Notice the gyro drift in the integrated gyroscope signal. It results from the small irregularities in the original angular speed. Those little deviations add up during the integration and cause an additional undesireable slow rotation of the gyroscope based orientation.

This entry was posted in programming, tutorials and tagged , , , . Bookmark the permalink.

94 Responses to Android Sensor Fusion Tutorial

  1. Paul says:

    Hello Hima,
    with the sentence you quoted from my article I basically wanted to point out that the filter obtains quick movements (short time intervals) from the gyro and slow movements (long periods of time) from the magnetometer/accelerometer. I deliberately do not quantify those time intervals since they depend on your use case, the involved sensors and the sampling rate you choose for your complementary filter.

    As for the filter coefficient and the time constant: At first, I tried to calculate them but eventually I ended up estimating them heuristically. I sent the fused sensor data through USB (using adb.exe from the Android SDK) on my desktop machine and rotated a 3D-representation of my phone on the screen. Then I started to adjust those constants until I got an acceptable result. I understand, when this response does not satisfy you. But if you understand the purpose of those two constants you more or less get an idea in which numeric ranges your constants need to be. TIME_CONSTANT is merely the time in milliseconds between two filter samples. It is _not_ the time constant of the filter in a sense of system theory. I admit, in this case the naming is unfortunate. SAMPLE_TIME would be a more approriate name, sice the “time constant” of a filter determines its cutoff frequency.

    So the actual filter time constant (tau) is calculated as:

    tau = filter_coeff * SAMPLE_TIME / (1 - filter_coeff)

    Inserting my values this yields a filter time constant of 0.147s. Which means that for time periods below 0.147s the gyroscope sensor data has more weight on the fused sensor data. For time periods above 0.147s the accelerometer/magnetometer values are more dominant. At this point I should refer to a presentation by Shane Colton which helped me quite a lot. I also mention this in section 5.4.1 of my master thesis.

    As for the calculation of your gravity vector:
    You can use the rotation matrix from the orientation data (e.g. determined by the sensor fusion) and perform an inverse rotation on the accelerometer vector to transform it into the world coordinate system. An inverse rotation is actually a multiplication of the vector with the transposed rotation matrix. Although, I think I saw API functions for this sort of calculations (I’m not sure).

    I hope I could help you

    Regards,
    Paul

  2. Harish Viswanathan says:

    Hi Paul,

    Thanks for this article. It helped us a lot. We used your code and we logged the acceleration, rotation matrix from the accelerometer and magneto, and also the Rotation matrix fused with the accelerometer-magneto and gyroscope. In addition, the Azimuth, pitch and roll were also logged.We linearly accelerated a car on a flat surface. We had placed the phone on a flat area besides the driver’s seat, so that the movements are minimum. Sometimes, we observe a strange phenomenon. There is an inflexion in all the three body angles, i.e. Azimuth, pitch and the roll. We are unable to figure out the reason for this inflexion. It would be great if you have a clue regarding this.

    Regards,
    Harish

  3. Paul says:

    Hi Harish,

    I’m glad to hear that the sensor fusion code was useful.
    Regarding your sporadic inflexion problem: With the current code I did not experience such a phenomenon, yet. Could you describe your observations in detail?

    To narrow down the problem I have following questions:
    - When the “inflexion”, as you describe it, occurs, does the measurement recover, or does it influence all following measurement data?
    - Do you move the vehicle in an indoor or outdoor environment? Could there be any magnetic interference on the track?
    - How does the phenomenon appear exactly? Is it just a quick glitch or is it perceivable over an amount of time?
    - What version of the code did you use? (there have been a few fixes).

    Honestly speaking, I can only make guesses on what causes the phenomenon. I perceived some strange behavior in an earlier version of the code, due to angle transitions from the beginning to the start of the angle value domain (which is fixed now). But since you’re saying that you encounter the problem on all three axes, this makes the whole thing look much more peculiar to me.

    Regards,
    Paul

  4. Diana says:

    Hi Paul,

    I’ve recently started working on my master thesis and your implementation of sensor fusion can possibly save me a lot of headaches. I don’t see any information about whether you allow copying and/or modifying your code. Because I want to avoid any troubles, I prefer to ask up front: Do you grant people permission to use and/or modify your code (GNU GPL)?

    I hope you can find the time to respond via e-mail. Thank you kindly.

    Kind regards,
    Diana

  5. Paul says:

    Hi Diana,
    I just added a license note to the code. It is now published under the MIT-License which allows you to do with it everything you want, which includes copying, modifying, republishing, selling etc.
    So, basically: permission granted ;) I wish you good luck with your master thesis.

    Kind regards,
    Paul

  6. manmohan badaya says:

    Hi Paul,

    I am trying to make app surface level finder using sensor.during start of this i found your code that helped me lot.currently i am able to move it to intermediate stage due to your code and some other stuff.but this code is not working on all android device.if i would say then it is not working on those device which are not present with rotation sensor.and one more problem i am facing that it roll (y axis rotation)is increasing very fastly when its pitch is near to -90 degree.actually i am unable to know this thing.I am beginner in android.so please if u know why i am facing these and how can i got solution for those..thanks for this nice code and thanks in advance.

    _
    with Regards
    Manmohan

  7. Paul says:

    Hi Manmohan,

    the above described code requires a gyroscope sensor in your device. So, it is true that it won’t run on all android devices. Actually, at the time I was writing this article the majority of android devices were not equipped with a gyroscope. The code is specially designed to stabilize the sensor data from gyroscope, so without a gyro there is no point in using it. If your device has only an accelerometer and a magnetometer (which most android smartphones have) you can use the sensor functions which are built in into the Android API to get the rotation of the device. Of course, this information will be less accurate than the information acquired with a gyro and a sensor fusion algorithm.

    Regarding your second problem: This is a common problem when using euler angles to represent the rotation of an object. It is called gimbal lock (en.wikipedia.org/wiki/Gimbal_lock) and happens when two rotation axes are in one line, which is the case when pitch is either 90 or -90 degrees. In this case the algorithm may behave strange. A solution would be to use quaternions instead of euler angles. Unfortunatelly, I did not have enough time to provide an implementation using quaternions. It would have been a more elegant approach.

    I’m sorry if I wasn’t a great help, but this is all I can currently say on this.

    Best Regards
    Paul

  8. Hi Paul,

    Great work, only the timerTask keeps running even if you close the app.
    I have tried to add some visualization to your source code and put it on the Market as a demo
    (probably available after 27-10-2012).

    Bye
    Zekitez

  9. Paul says:

    Thanks, Zekitez.
    I know, the code is suboptimal in many regards. Originally it was intended just for demonstration purposes.

  10. abbas says:

    Thanks Zekitez
    I was very helpful, I just want to know can \i have the source code package.can you please send to me.
    thanks

  11. zia says:

    Hi Paul,

    It really helps alot, can I get the latest version of the code.

    thanks.
    Zia

  12. Paul says:

    Hi Zia,
    You can download it directly in the article. There were no updates recentyl.
    Regards,
    Paul

  13. zia says:

    Hi Paul,

    I have used your sensor fusion code and I really appreciate your efforts. In this regard I have one question.
    I have the purely raw Orientation (Acc+Mag) sensor data,i.e, Azimuth, pitch and roll. I tried to compare the result of Orientation (Acc+Mag) data with sensor fusion Azimuth of your code but I am facing a problem.

    Problem: A trajectory is made on a ground (heading of the trajectory is known). The device is placed stationary on the trajectory parallel to the surface of earth. The orientation Azimuth (Acc+Mag) sensor data and sensor fusion Azimuth (from your code) remains stable and correct with respect to ground heading trajectory.

    When I tilted (Pitch) the device at a 70 degree on a known true ground heading, the Azimuth from both approaches remains same and stable with the ground heading. As soon as I increased the tilt (Pitch) to 90 degree the Orientation azimuth (Acc+Mag) becomes stable with respect to ground heading but sensor fusion azimuth (from your code) got crazy and deflects from the ground heading by 90 degree and sometimes 180 degree. While the orientation azimuth (Acc+Mag) remains stable with the ground heading.

    I hope you understand my query and provide me a solution. BTW, Can I have a mathematical model of your approach.

    Regards
    Zia

  14. Paul says:

    Hi Zia,
    I’m currently a little bit tied up, so I won’t be able to investigate the issue in the near future (but I hope eventually I will). It is possible that the code I provided for the article still has some issues with the gibal lock situation. I didn’t go in depth in this regard, since it was not a requirement for my use case.

    I haven’t worked on any detailed mathematical description of the algorithm so far, but I agree, it would be helpful and interesting to have one (well, it also depends on how elaborate you want the model to be). However, I cannot guarantee that I will provide a mathematical model, since I have very little time on my hands at the moment.

    I’m sorry that I couldn’t help you. But I will come back to this issue as soon as I’m given some time. Until then, I’m afraid, any work related to sensor fusion is on hiatus.#

    Regards
    Paul

  15. Philipp says:

    Hallo Paul,

    danke für dein Tutorial!

    Könntest du mir sagen, ob du weist, ob es eine Möglichkeit gibt das für Processing umzubauen, so dass es da auch funktioniert?

    Vielen Dank!
    Philipp

  16. Paul says:

    Hi Phillip,
    ich selber habe mit Processing bislang noch nicht gearbeitet, aber schon vieles darüber gehört und gelesen. Von daher weiß ich nichts Definitives. Aber ich kann mir sehr gut vorstellen, dass es sogar mehrere Möglichkeiten gibt, einen Sensor-Fusion-Algorithmus mit Processing zu verwirklichen. Wie sehen denn die Schnittstellen zu deinen Sensoren aus, wenn du eine Anwendung in Processing programmierst bzw. was für Sensoren verwendest du?

    Grüße,
    Paul

    P.S.: Wieder einmal, sorry für die verzögerte Antwort :-/

  17. Michelle says:

    Hi Paul

    Thank you very much for explaining a complicated topic. I downloaded your code and it ran without throwing any errors on my Samsung Galaxy S3 (4.1.1). However, I am looking at the values of Azimuth right now with the Orientation from Sensor Fusion radio button selected and the phone is lying flat on my desk. The values have ranged from -119 to 189 and they keep changing super fast and I’m not even touching the phone. Nothing large and metallic is sitting nearby. I was just wondering what kind of output should I be expecting to see. That much variation makes it difficult to use the data so something must be off. The Pitch and Roll keep changing too, with all numbers changing so frequently, it is difficult to even read them at times. Any ideas what I should be investigating?

    Thanks very much and I understand you are super busy so all I’m hoping for is perhaps an idea or path that I can follow, not expecting you to code a solution :)

  18. Android Developer says:

    Hi there,
    First off, thank you for taking the time to publish this tutorial. It’s been really helpful for me in developing my Android app. :D I have two question regarding the gyroscope right now:

    1. Your code only seems to work accurately when the device is placed parallel to the ground (flat on a table/on my hand, etc.). How do I get it to work when the device is placed in any position? For example, I would like to have it work when the device is placed completely upright. When I do this however, the pitch readings go to 90 degrees, which tells me that the device is using a parallel position as its initial position for the gyroscope. Also, when I move the device from its “parallel to the ground” position to another position, the roll angle readings become inaccurate. How can I get around this problem?

    2. Is there any way to change the sensitivity of the gyroscope? I would like to make it so that the readings come out faster, thus making my whole app seem more responsive. Right now, it feels a bit sluggish.

    Any advice is appreciated. Thanks again for your hard work and help! :D

  19. Paul says:

    Hi Michelle,
    I cannot explain the behavior you are describing. On my phone (Galaxy S2 Android 4.0.4) the azimuth value fluctuates by +-1°. When lying flat on the desk the pitch and roll values have an error of +-0,2°. This is acomplished by the code you can download from the article. Are you sure everything is ok with your hardware? Sometimes the magnetometer has strange deviations and I get rid of them by shaking the phone for a few seconds (don’t ask me why this is working).

    Did you modify the code in any way or did you use it as it is?
    Maybe the API changed from 4.0.4 to 4.1.1, but I can’t tell for sure.
    I’m afraid I cannot give you any further clues without additional information. I’m sorry :-/

  20. Paul says:

    Yes, the app is programmed in a way that the normal vector of the display plane is used as the up-vector (i.e. the z-axis as described in the API documentation: http://developer.android.com/reference/android/hardware/SensorEvent.html). However, this should not have any unexpected influence on the readings when the phone is turned upright. So the code should work in any position with the same accuracy. If you want to have the upright position as the initial one, you will have to rotate your frame of reference accordingly. The simplest way would be to rotate the resulting rotation matrix by -90 degrees about the x-axis. But you have to be careful about at which point in the algorithm to apply this rotation. Always remember that rotations are not commutative operations. To be more specific on this, I would have to review the code again, since I haven’t workt with it for a while now.

    Regarding the inaccuracy of the roll value in upright position:
    This is quite obvious. When the device lies flat on the table the magnetometer is used to calculate the azimuth angle and pitch and roll are supported by the accelerometer. So the deviations in the azimuth value are greater, since the magnetometer is noisy and less accurate. If you hold the device upright the magneotmeter has stronger influence on the roll angle, while the azimuth angle is more accurate.

    Regarding your second question:
    There are different accuracy settings in each of the sensors (see link above), but I don’t think that this is what you have in mind. You can adjust the sensor fusion algorithm to be more responsive to quick changes by increasing the FILTER_COEFFICIENT constant. But keep in mind that this value should never be greater than 1.0, otherwise you will get unexpected results. You can also play around with TIME_CONSTANT and try to increase the sample rate. But then you will have to decrease the FILTER_COEFFICIENT at the same time to get accurate results. It is a matter of balance.

  21. Szymon says:

    Hi Paul!
    Thank you very much for this tutorial. It’s one of the best in my opinion about sensor fusion on android. I am currently trying to use your algorithm in augmented reality application. My app supposes to print on the mobile phone screen some GPS locations. To do this i need to have the device orientation, where your tutorial came extremely helpy. However, since I need to augment the displayed GPS locations on the preview from the camera, i need to remapCoordinates, since I need to have the direction (azmuth) in witch the camera points. To do this, for the rotation matrix taken from sensors I did as it was in the (: SensorManager.remapCoordinateSystem(rotationMatrix,
    SensorManager.AXIS_X, SensorManager.AXIS_Z,
    myNewRotationMatrix);

    I thought I can do the same with rotation matrix calculated for the Gyro, but after that strange things started to happen. Why is that?

  22. Paul says:

    Hi Szymon,
    the problem is, that you need to remap the rotation matrix after the sensor fusion. If you remap the gyro orientation matrix, the gyro data and the accelerometer/magnetometer data will contradict each other and the algorithm goes nuts. In my code example the fused orientation is stored in the gyroMatrix variable, but this is done in order to have a stable initial orientation for the next calculation. Just take the fused orientation right after the sensor fusion calculation and store it in a separate member or local variable:

    float[] myOrientationMatrix = getRotationMatrixFromOrientation(fusedOrientation);
    SensorManager.remapCoordinateSystem( myOrientationMatrix, … // you know the rest

    Hope this helps.

    P.S: Augmented reality sounds very exciting to me by the way ;)

    Best Regards,
    Paul

  23. Muhammad says:

    Great tutorial, i would like to know what portion of code is complimentary filter, I would like to use to use KALMAN Filter instead.

  24. Pingback: Gyroscope Issues with Device Orientation video

  25. Paul says:

    Hi Muhammad,
    the actual filtering calculations are performed within the calculateFusedOrientationTask in the code. I’m afraid you would have to restructure the whole application to implement a working kalman filter (of some sort) since this approach is much more complex (and mainly unknown to me).
    Regards,
    Paul

  26. Marzieh says:

    Hello Paul,
    I’m working on a project now and looking for an application to log the direction/heading indoor.
    I found 2 Compass data recorder based on GPS which is not not working indoor.
    Do you know if there is any application available now or I should write it?
    Thanks for your time in advance.

    Cheers
    Marzieh

  27. Paul says:

    Hi Marzieh,

    I don’t know if there are any applications or libraries/code snippets out there which fit your needs. If I were you, I would write my own simple logging mechanism for the date you receive from your sensors, since you will be abe to adapt the data model easier when required. But that of course depends on the time budget you have on your project.

    Cheers,
    Paul

  28. michal says:

    Paul – your article is REALLY THE TUTORIAL. Great and life saving. Thank you!

    I would like to ask abou linear acceleration. Some people here were discussing this topic. My question: is getting correct orientation (like the one after fusing here) is the only way leading to calculating linear acceleration? I mean: do I need current orientation? Sorry for spoon-feeding question but I want to implement my own LA and trying to get options I have doing this.

    Any advice on further way would be great!

  29. Paul says:

    Hi Michal,
    thank you for your commendation, I’m very flattered.
    To be honest, I never implemented linear acceleration for an android device. So what I’m telling you is pure theory.
    Getting linear acceleration is quite tricky because, as you said, you require the device’s orientation in order to get rid of the gravity vector wich is already applied within the acceleration vector (Same problem when trying to measure gravity but the other way around). It also depends on how much you expect the device to change orientation during linear acceleration measurement. If your device is moving AND rotating continuously (and slowly), I beleive that even the sensor fusion approach will fail at some point. The simplest way to go about it (without sensor fusion) is to get the device orientation from the accelerometer and magnetometer at the very beginnig of the measurement and use it as reference for linear acceleration measurement. Downside: you may not rotate your device because this will change your reference orientation thus making your acceleration inconsistent. So I believe this is not an option for you.

    With sensor fusion however you have a gyro-component in your orientation measurement which is independent from acceleration. But your fused orientation will always be biased by the skewed acceleration vector when moving the device. So no matter how you turn it (metaphorically ;) ), there will always be some dirt in your measurement. It depends on how much “dirt” you are willing to accept, how accurate you want to be. You could try to increase the gyro-component in the filter algorithm so the accelerometer component doesn’t distort your orientation too much. However, don’t forget the gyro-drift problem for which we fused the sensor data in the first place.

    As you see, it is not a trivial problem and I’m afraid, since I did not dwell in it very deeply, I cannot provide you with an ideal solution. I’m also not sure whether sensor fusion is the only solution for this problem, neither do I know whether it is a viable approach at all (since I did not test it). All I can do is provide you my thoughts on it.

    I hope you find a solution that fits your needs. And if you do, don’t hesitate to share it with others :)

  30. josean says:

    The best way to integrate data coming from various sensors is through a Kalman filter.
    I would suggest you to have a look at this compass, in particular if your smartphone includes a gyroscopic sensor.
    Anyway, congratulations for such an excellent article.

  31. Joe Marshall says:

    Nice tutorial. It is probably worth pointing out briefly somewhere near the top of this article, that on a more recent version of Android (Ice Cream Sandwich or later), the Android framework does all this magic for you, using a quite nice Kalman filter based method. Rather than use the raw accelerometer/gyro etc. data, you can use the ‘virtual sensor’ types:

    TYPE_ROTATION_VECTOR – orientation of device (from a fusion of accelerometer, magnetometer and gyroscope, as your code does, but using a Kalman filter)
    TYPE_GRAVITY – direction of gravity relative to device (from the same fusion)
    TYPE_LINEAR_ACCELERATION (pure linear acceleration of device with gravity removed – done using the above orientation calculations)

    Oh, and if you want orientation from TYPE_ROTATION_VECTOR, you do it like this:
    SensorManager.getRotationMatrixFromVector(m_RotationMatrix, m_RotationVectorVals);
    SensorManager.getOrientation(m_RotationMatrix, m_Orientation);

    You can download a demo app called ‘sensor fusion(demo)’ from the play store, which shows it off, it is surprisingly stable (like <0.1 degree angle jitter when I leave the phone still on a table) and extremely fast to respond.

    The code behind it is all here:
    https://github.com/android/platform_frameworks_base/tree/jb-mr0-release/services/sensorservice

  32. Thanks you very much for this excellent code.
    I use it to control my Balancing robot I just published at Kickstarter: http://www.kickstarter.com/projects/tkjelectronics/balanduino-balancing-robot-kit.
    And here is the source code for the Android application: https://github.com/TKJElectronics/BalanduinoAndroidApp.
    Thank you once again!

  33. Paul says:

    @Joe:
    Thanks for pointing that out!
    I wondered how long it would take for google to actually add this feature to their framework. Apparently iOS already had something like that at the time I published this tutorial. As yet I had no time to really understand Kalman filters. But I heard this is the best way to achieve stable and accurate orientation data.

    @Kristian:
    Cool stuff! I’m impressed! I wish you good luck with your campaign.

  34. Moustafa Alzantot says:

    Hi,

    Thanks for the great article.

    I have adoubt about the LPF equation,
    I think a (1-factor) term is needed to be multiplied by the old accMagOrientation value on the LHS, so that the equation be :

    accMagOrientation = accMagOrientation + factor * newAccMagValue;

    is that right ?

  35. Paul says:

    Hello Moustafa,
    yes you are right. The total multiplicator should add up to a factor of 1.0. I made a mistake there. I’ll correct it in the article. Thanks for pointing it out!

  36. phildar says:

    Hi !! congratulations for your work ! I made a processing sketch of it if some of you are interested, I can share.
    I would have liked to know how to compensate the roll from sensorfusion datas? I have an installation which requires just the pitch and azimuth. thanks
    p.

  37. Paul says:

    What exactly do you mean by compensating the roll? If you don’t need the roll information, just leave it out or set it to a default value (e.g. 0 degrees).

  38. phildar says:

    Thanks for your reply.
    I have my tablet in landscape orientation. I move around a statue which is at the center of the installation. (The azimuth gives me the spherical position from 0 to 360°).
    When I change to portrait orientation, the azimuth changes ! and the position goes wrong.
    How could I avoid this ?

  39. Paul says:

    It’s still not clear what exactly you’re asking for. Is the tabled lying flat in front of you or are you holding it upright? What exactly is the installation you are talking about? Is it an object you are capturing with the tablet’s camera or is it a virtual 3D-object in a scene of your application you are showing on the display? Are you moving your statue or are you rotating it?

    Please take into account, that all rotation axes are fixed with the device’s frame. The axis-conventions are defined here. If you are holding the device upright in front of you in portrait mode an turn it about the vertical axis (which is Y, in that case) you are changing the roll angle. If you are halding it upright in landscape mode the vertical axis is x and you are changing the pich angle.

  40. phildar says:

    thanks_my post was not cleared .
    I have an app which is forced in landscape mode. in portrait mode your code give good results.
    But when I am in landscape, sensors are crazy. How could I set true islandscape() in your code ?
    thanks in advance.

  41. Paul says:

    you need to transform the coordinate system according to the given display orientation. The app is coded for portrait mode so translational coordinates are mapped as follows – assuming you rotate your device 90° counter-clockwise:
    (portrait) x –> (landscape) y
    (portrait) y –> (landscape) -x
    (portrait) z –> (landscape) z

    Now these are just the axes. My code provides angular information in respect of these axes. We need to take that into account too:
    (portrait) pitch (x-rotation) –> (landscape) roll
    (portrait) roll (y-rotation) –> (landscape) pitch

    However, since I’m using global coordinates in my code, I’m not sure if the above mappings apply correctly.
    Maybe you’re better off by creating a static rotation matrix that rotates the orientation result by -90° around the local z-axis.
    Don’t know if that works either, since I haven’t tested it.

  42. phildar says:

    Thanks a lot for your response !
    actually remap coordinates doesn’t seem to work :

    public void calculateAccMagOrientation() {
    if (SensorManager.getRotationMatrix(temp, null, accel, magnet)) {
    SensorManager.remapCoordinateSystem(temp, SensorManager.AXIS_X, SensorManager.AXIS_Y, rotationMatrix);
    SensorManager.getOrientation(rotationMatrix, accMagOrientation);
    }
    I’ ll try to make a rotation matrix of -90° from z axis. Do I have to do it in calculateAccMagOrientation ?
    thanks .
    p.

Leave a Reply

Your email address will not be published. Required fields are marked *


eight − = 6

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>