I am trying to use the phone as a gun aiming with the gyroscope. I calibrate with the phone or tablet in a certain orientation. This will shoot straight. Then depending on the direction the phone is turned (left/right/up/down.), the gun shoots in that direction.
I am using the gyroscope. And all this works. Except after shooting for about 30 secs, the gyroscope slowly starts drifting towards left or right. So when I go back to the orientation I calibrated with, it doesn't shoot straight anymore. Does anyone have any experience writing a Complementary or Kalman Filter to fuse gyro and accelerometer data to give better results in Unity 3D?
I've found this online - http://www.x-io.co.uk/open-source-ahrs-with-x-imu/. It seems to do exactly what I want. But I am using it wrong. I sometime get better and sometimes get worse results with. Anybody have any experience with it ?
First place, Gyro/accelerometer fusion will stabilize your pitch/roll angles, since gravity indicates in which direction ground is. However, you cannot correct "left/right" drift because actual heading is unknown. Getting proper heading stabilization cannot be achieved with gyro/accelerometer alone: it requires additional information.
The example you provide (Madgwick’s MARG/IMU filter) is a filter that can integrate magnetometers ("north" reference), but it has two requirements for getting good results:
The magnetometer has been properly calibrated.
There are no magnetic field disturbances. This is generally not true if you are indoors, or if you are moving close to power lines or metallic structures.
An alternative is using a video signal to get optical flow information, or detecting if the phone is resting in a fixed position to compensate gyro biases from time to time.
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 currently doing an application to detect potholes on the road through the accelerometer in the phone. The problem I have is that I need to reorient the accelerometer axis to align with the cars axis.
I found this explanation below from a report online but I do not know how I use the GPS to calculate the post-rotation and how to monitor the pre-rotation angles.
The explanation online:
"The phone can lie at any arbitrary orientation and, hence, it’s
embedded accelerometer. Therefore, it must be oriented along the vehicle’s axis before
analyzing the signals. This system uses an algorithm based upon Euler angles for
reorientation. The sensor is virtually rotated along the vehicle’s axis using pre-rotation,
tilt and post-rotation angles (Euler angles). The post-rotation angle is calculated using
GPS, so to avoid extra energy consumption the pre-rotation and tilt angles are
monitored continuously and whenever there is any significant change in these angles,
GPS is turned on and reorientation process is done again."
I have searched for ways to find the device orientation with phonegap but all I can find is the heading orientation plugin which seems to be used to give the compass direction of the phone.
Any advice or even an alternate way of doing this would be greatly appreciated.
I found the ebook "Pervasive Computing: 10th International Conference, Pervasive 2012 Newcastle, UK" useful for understanding how to program the reorientation of the accelerometer axis's.
Here's a link to the page in the book that describes the process: https://books.google.ie/books?id=VTy6BQAAQBAJ&pg=PA7&lpg=PA7&dq=pre-rotation,+tilt+post-rotation+matrices&source=bl&ots=Py9GXtE7Io&sig=xfur3P7sv_XaR9ihOAsPXvgGiWw&hl=en&sa=X&ved=0ahUKEwiCmc3V0YfLAhXFPRoKHZuODpMQ6AEIKDAC#v=onepage&q=pre-rotation%2C%20tilt%20post-rotation%20matrices&f=false
Hope this helps anyone else trying to do this.
I'm developing an app that uses Android sensors to help vehicles navigate in an indoor location. As part of my evaluation process of different sensors, I wanted to try the "rotation vector" sensors. For various reasons, magnetic field readings are not very useful for my location, so thus I wanted to try the "Game Rotation Vector" sensor (sensor fusion, available from API level 18 and later). The description states that it is identical to the regular Rotation Vector sensor except no magnetic field information is used to correct for gyroscope drift around the vertical axis.
When looking for information about the Rotation Vector sensors, I came across an example from Google, where they show the Rotation Vector sensor using a 3d cube. It works pretty well, except for being very sensitive to local magnetic fields (and me being far north, even worse, since the horizontal component is very small here).
Since long term drift can be compensated by other reference data (map information), I wanted to use the Game Rotation Vector sensor for my app. However, when changing all references from "TYPE_ROTATION_VECTOR" to "TYPE_GAME_ROTATION_VECTOR" in the example code, the cube no longer reacted to rotations around the vertical axis (eg. me spinning my chair, holding the device in front of me). Tilting the device in the other two directions moved the cube. I also noticed the cube was a lot more "laggy" this time around, reacting very slowly to any movement.
Is this the way the Game Rotation Vector sensor is supposed to work (eg. ignoring any Z axis rotations)? It would kind of make sense, since a gamer playing in the back seat shouldn't be affected by the vehicle turning, but at the same time it differs from the description provided by Google (my first link). From the description I was under the impression that it would drift slowly, not ignore rotation all together.
I would be deeply grateful for any input on this issue.
Best Regards,
John
Ok, just in case anyone happens to find this, here are my findings:
The Game Rotation Vector sensor does detect rotation around the vertical axis. It is quite accurate in most situations.
However, it has a couple of issues... First, while lying still it has accelerating horizontal drift (even when a gyroscope-based orientation has linear drift). For my device, Game Rotation Vector started out good, but accelerated and finally drifted more than 400 degrees over the course of an hour.
Secondly, and even more disturbing, it does not seem to ignore magnetic fields, contrary to the official description (linked in the question). I tried driving around the parking lot with my device fixed on the passenger seat, and the Game Rotation Vector fell behind largely (it was more than 180 degrees off after one full rotation over 40 seconds), while integrated gyroscope data was accurate within a few degrees. It also showed changes in rotation when the gyroscope was hovering around zero, suggesting that it was in fact compensating for a change in (what I presume to be) magnetic field.
I still don't know why it acted wierd in the test app I linked to before, but I have since decided to use a complementary filter to combine accelerometer and gyro data instead.
I'm trying to write a small android game where the phone is placed on the table.
On the screen there is a ball, which the user control its movement by moving the phone.
Along all the game the user won't lift the phone from the table.
At the beginning the ball will placed in the middle of the screen:
Pushing the phone from the user:
should move the ball toward the top of the smartphone screen:
And from the current position of the ball, moving the phone back to the user, and to the right:
will move the ball accordingly:
I read the Android Motion Sensors Guide carefully but I didn't even realize what Sensor \ Sensors should I use.
I would love to get any directions.
First of all TYPE_LINEAR_ACCELERATION, TYPE_ROTATION_VECTOR, TYPE_GRAVITY are not physical sensors but made from sensor fusion.
Secondly from Android 4+ these fused sensors make use of device Gyroscope, so they WON'T work if the mobile device doesn't has a gyroscope.
So if you want to make a generic app for all phones prefer using only Accelerometer (TYPE_ACCELEROMETER).
Now for your case since user won't lift the mobile from table, and if you want you can easily subtract the Gravity component from accelerometer. See http://developer.android.com/reference/android/hardware/SensorEvent.html
under section Sensor.TYPE_ACCELEROMETER. (Code is given too).
Now you can see How can I find distance traveled with a gyroscope and accelerometer? to find the linear displacement & the 1st answer states their is NO use of Gyroscope. (Or you can just google for finding the displacement/Linear velocity from acceleromter readings)
Hope this all would give you quite lot an idea.
It's really difficult to do this type of linear position sensing using the types of sensors that smartphones have. Acceleration is the second derivative of position with respect to time. So in theory, you could use the accelerometer data, integrating twice in time to achieve the absolute position. In practice, noise makes that calculation inaccurate.
On the other hand, if you're really talking about putting the camera facedown on the table, maybe you can come up with some clever way of using OpenCV's optical flow features to detect motion using the camera, almost like an optical mouse. I don't know how you would light the surface (the flash would probably burn through the battery) but it might be possible to work something out.
I'm using the Android SDK (2.2) with a Droid and I have access to the 3-axis accelerometer and gyrometer.
I apologize in advance if this reveals my ignorance of physics. It has been awhile.
What I don't understand is why the accelerometer is giving different x,y,z values when I tilt the phone. It's standing still, at least, with negligible acceleration and even mostly constant velocity, it's just tilted. I thought that this was the gyrometer's job?
I don't want gravity in the equation...I just want the other forces affecting the phone. Everything had better be 0,0,0 unless I'm moving it faster. I want to know how hard I hit the phone on the table, and the direction and magnitude of the x,y,z forces when I do so. So far, I am confused beyond belief about how to access this with the accelerometer and gyrometer data. I'm trying to take the gyrometer as the direction and the accelerometer as the magnitude. Unfortunately, the data for those aren't really in sync (I have to setup two events to get each pair of data, and they may come at different times), but it might be good enough to just buffer them and assume some sort of synchronization.
Desperate,
Andrew
I'm afraid that's just how accelerometers work, here on earth there will always be 9.8 Gs pointing at the ground.
If you can assume that you have a working compass, just take a vector of length STANDARD_GRAVITY, rotate with the current orientation taken from the magnetometer and subtract this from your accelerometer's vector.
Keep in mind that you should also dampen the values you get back from the accelerometer, use a running average of the last few values.