I need to build compass for my application.
From reading the documentation it seems there are two reasonable ways of doing this:
Sensor.TYPE_ORIENTATION method: This is the easy way of doing it. The problem with this is it is not accurate. When I compare my reading with Snaptic Compass it is about 10-15 degress off which for my purposes is unacceptable.
Sensor.TYPE_ACCELEROMETER, Sensor.TYPE_MAGNETIC_FIELD and getRotationMatrix() in conjunction with remapCoordinateSystem() and getOrientation() method: The documentation says this "is usually more accurate". The problem is regardless of the delay I register with listener the compass goes crazy even when the device is stationary on flat surface.
Any suggestions for solving this problem will be greatly appreciated.
Looks like mob1lejunkie has figured this out already, but just for future reference, let me mention that the issue here is magnetic declination (the difference between magnetic north and true north). You can try out an online model from NOAA to get a sense for what the difference is in your part of the world.
Android includes a model called GeomagneticField that can be used to compute the approximate declination given a latitude, longitude, and altitude. So, what I believe you need to do to compute true north is read out the azimuth value from Sensor.TYPE_ORIENTATION and then add to that GeomagneticField.getDeclination().
It's the downside of compact parts made for phones. A $5000 IMU that we're using right now has an error of +/- 2 degrees and in that range it seems to go crazy as well.
Try stepping away from interference, metal surfaces, and see if it improves. If not, I hate to break the bad news, but that's the hardware.
Have you seen these?
http://developer.android.com/reference/android/hardware/SensorManager.html
http://groups.google.com/group/android-developers/browse_thread/thread/bbb0e8b97c673cf9/5c16bc2e49f6e972?lnk=raot
Related
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?
Error you ask is caused because of Euler angles or called Gimbal Lock.
To solve very high angle difference, you should check if your device is flat or not checking inclination after getting inclination using gravity sensor or getting gravity from accelerometer with lowpass filter. If it's not flat(AR application or inclination>25 || inclination < 155) remap coordinate system from x,y to x,z. That will solve the issue.
SensorManager.getRotationMatrixFromVector(rotationMatrix, event.values);
SensorManager.remapCoordinateSystem(rotationMatrix, SensorManager.AXIS_X, SensorManager.AXIS_Z, remappedRM);
SensorManager.getOrientation(remappedRM, orientation);
This solves the Gimbal Lock, however, 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. I haven't able to solve it. Mostly difference is between 1-5 degrees but i sometimes see it rise up to 10 degrees which is not acceptable.
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.
List of ways doing a compass with the most accurate to least is in order
Use GPS/Wife(Google's fused location) location and get bearing from location
Use Rotation Vector(requires magnetic field sensor, you should check if it's available), it's a fused sensor(magnetic field+gyroscope+accelerometer and software parts) and using Kalman filter to smooth values but check inclination to remap orientation
Gravity/Accelerometer + Magnetic Field Sensor. This will have a terrible noise attached to it, to smooth it you should use moving average or low-pass filter(this not for isolating gravity, it's for using a threshold frequency to prevent high jumps)
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."
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).
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.
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.
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
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.
I am working on an Android app and I am trying to figure out how can I combine accelerometer and magnetometer to find the walking direction of the user when indoors. I understand that I can only get an approximate direction and not the real value. :)
Any ideas? Would gyroscope also help in this case?
Thanks
The user's acceleration is nearly zero most of the time, therefore, walking will produce a predictable pattern. This general property serves as something like an anchor point, from which other stages of the walk can be analyzed.
With this in mind, i think a position classifier to detect where the phone is located on the body is needed. After that you can measure the angle between the phone position and the magnetic north of the earth.
But be aware, for an accurate measure, it will need an enormous filtering.
don't know what kind of direction you mean but might possible SensorEvent helps you what your are looking. SensorEventListener is being used to build compass app.
https://developer.android.com/reference/android/hardware/SensorEvent.html
I have a question regarding inertial navigation with a mobile device.
I am using an android tablet for development but I think the question is related to
all types (even with better sensors) of hardware.
The most basic question when developing an inertial system is how to determine the
direction of the carrier's movement.
Even if we assume that the magnetometer readings are 100% accurate (which they are obviously not!) There is still the question of the device orientation relative to the user.
Simple example - if the user is walking north, but holds the device with the device's Y axis points north-east, (a link to a picture of the different axis: http://developer.android.com/reference/android/hardware/SensorEvent.html)
Then the magnetometer will point towards north-east.
How can we tell which way the user is actually heading?
(The same will be true if we use both magnetometer and Gyro for determining heading)
A possible solution will be to use the Accelerometer's Y-axis and X-axis readings.
Something in the direction of using arctan(a-Y/a-X)
(for example - if the user holds the device perfectly straight, then the X-Axis will show nothing...)
But since the Accelerometer's readings are not stable, it is not so easy...
Does anyone know of an algorithm that actually works? I am sure this is a well known problem, but I can't seem to find references to solutions...
Thanks in advance!
Ariel
See this answer for an idea: by obtaining the acceleration values in relation to the earth, you can then use the atan2 function to compute the actual direction.
You mention the user holds the tablet, and I assume fairly stable (unlike a case I am working on, where the user moves the phone constantly). Yet, for some reason, the user may change the orientation of the device, and this may influence the readings you obtain.
Thus, in the event of an orientation change, you should call remapCoordinates() accordingly to fix the readings you obtain.
NOTE: You can also use the getOrientation() method accordingly, and the first field represents the heading direction.
The really right answer is to leave the device sitting there for a while, detect the rotation of the earth, and then compute true north from that. Unfortunately, the gyros in a mobile phone aren't accurate enough for that....
I'm using an Android device to get the heading(azimuth, or yaw angle).
Android API used the Accelerometer value + the mganetic field to compute a matrix rotation, the azimuth is then extracted form that matrix (aka SensorManager.getOrientation(...)) But the result is very inaccurate! especially if the phone is perturbed by some magnetic stuff.
And then I have the Gyroscope, If I integrate the value of the gyro trough time, I'm able to get an actual Angle, but like everybody knows :p, this is subject to drift... after 10 seconds even tough I'm not moving the angle drifted of 10°...
So here I have in one side the result of the accel + magneto, it's quite crap near magnetic field
and on the other side I have the result of the gyro that are really good, but drift over time...
So my question is, is there an easy or smart way to combine the two results together to get a kind of "robust" heading estimation? I say easy because I know there is kalman filters.. but even tough i read the theory 50 times I can't get a damn thing :).
Thank you!
As far as I know, either the Kalman filter or something similar is implemented in the SensorManager. Check out Sensor Fusion on Android Devices: A Revolution in Motion Processing.
You are trying to solve a problem that is already solved.
TO make it short:
It is not possible to combine Gyroscope + accelerometer TO GET THE AZIMUTH (I precise) Simply because the accelerometer can't sense acceleration on the XY axis..
A method would be to fuse the Gyroscope with the Compass but that won't work really good if there is magnetic pertubation
It seems to have a very generalized confusion about gyroscope sensor. I have recently answered a similar question here, so I recommend to anybody interested in these topics to have a look at that question and answer.
I have used the described technique in this application (a compass which integrates gyroscope readings to improve results). The result is not perfect, but is much better in general than other compasses.
this is another question about indoor tracking using inertial (smartphone + aceel + gyro)
Firstly, I would like to say that I have read almost every post on stackoverflow talking about this subject.
And I know that to track a position We will have to integrate TWICE the accel and that is very useless in a real life application because of all the drift errors...
But it turned out that I don't need to build a plane or whatever And i don't need to develop an application that have to WORK to be sold or something. I just want to realize a simple Android App that use "theoretical" concept of an Indoor tracking-
What's the possibilities?
What do we need?
Basically my phone is resting on a desk screen facing UP at a known position (0,0) if a push my phone to 2 or 3 meters and then I rotate it and push it again for 2 or 3
meters I the to see after how many meters it becomes to inaccurate an so use a tag tu recalibrate the measurements <--- That's my main question
what do I need ?
- the angle ? (ok integrating the the gyro) (i don't wanna use the compass)
- the accel? (i have)
- the velocity ? (integrating the accel)
- and the position (double accel integration)
The thing that I would like to know is How can I put this number together? Is it the right way to do it? Is there another solution (to resolve my problem, not to track someone really accurately)?
I also looked at the theory of the DCM (If I understood correctly, it will give me the orientation of the phone in 6 axes right? But what's the difference about getting the angle from the Accel or the gyro (pitch, roll etc..) ?
Thank you
Your smartphone probably has a 3-axis gyro, a 3-axis magnetometer and a 3-axis accelerometer. This is enough for a good estimation of attitude. Each has its advantages and disadvantages:
The accelerometers can measure the gravity force, it gives you the attitude of your phone, but in a horizontal position, you can't know where it's pointing. And it's very sensitive to inertial noise.
The gyroscopes are fastest and the most accurate, but its problem is the drift.
The magnetometers don't have drift and they aren't sensitive to inertial forces, but are too slow.
The combination of the three give you all advantages and no disadvantages. You must read the gyro measure faster as you can (this minimizes the drift) and then use the slow and not as accurate measure of magnetometer and accelerometer to correct them.
I leave you some links that may interest you:
A Guide to using IMU: http://www.starlino.com/imu_guide.html
DCM tutorial: http://www.starlino.com/dcm_tutorial.html
I hope I've been helpful and sorry for my bad English.
With the sensors you have, not considering computational power at this point yet, I know of only one method of position / displacement estimation. This would either involve just optical flow with the onboard camera, or the above with addidional info from fused data from accels / gyros (eg. with a Kalman-Filter) to improve accuracy. I guess OpenCV has all you need (including support for Android), so I'd start there.
Start by implementing an attitude-estimator with just accels and gyros. This will drift in yaw-axis (ie. the axis perpendicular to the ground, or rather parallel to gravity vector). This can be done with a Kalman-Filter or other algorithms. This won't be any good for position estimation, as the estimated position will drift tenths of meters away in just a couple of seconds.
Then try implementing optical flow with your camera, which is computationally expensive. Actually this alone could be a solution, but with less accuracy than with additional data from an IMU.
Good luck.
EDIT: I recently found this - it may be helpful to you. If there is not a lot of noise (due to vibration), this would work (I'm on a quadrotor UAV and it unfortunately doesn't work for me).