Accelerometer QML - android

Attempt to measure distance based acceleration (accelerometer mobile). If that's true
Accelerometer {
id: accel
dataRate: 1000 / 25
onReadingChanged: {
console.log(reading.x, reading.y, reading.z);
}
}
In console
D/libsensor.so(16533): qrc:/main.qml:20 (onReadingChanged): qml: 1.359906554222107,8.791508674621582,-0.4405331015586853
Now when you display information and having the mobile completely still (motionless). Shows acceleration in all axes, which is absurd! You have any idea why?

That's certainly not absurd.
According to Einstein's widely accepted (but still disturbing) theories, your phone can't tell if it's sitting still on planet Earth or accelerating inside a spaceship in deep space - that's called the "equivalence principle". So it's just assuming it's in an accelerating spaceship, because why not ? And that's so much cooler, don't you think ?
If you're near (or on) a planet and reading a zero acceleration, that's bad news, because that means you're freefalling in the distorted spacetime around the planet, and you're probably about to hit something.
You're reading an acceleration of about 9m/s^2, which is close to Earth's g value, so that's approximatively right, depending on your phone orientation. Maybe the accerelometer calibration is not quite right, you can test it with a dedicated application, if you've not done it already. NB Some apps will compensate for the gravity of Earth.
Of course, there's also the possibility of bugs in the phone or in Qt or in your code, or hardware failure, but you have to know what to expect.
Hope that helps.

Related

Detect vibration with Android accelerometer

I'm trying to detect patterns of knocking on the surface that the device is located on.
For example, if a user knocks one time on the surface, run method A. If the user knocks two times, run method B.
I have everything I need to make this happen except for the logics in the onSensorChanged method.
This is my code right now:
#Override
public void onSensorChanged(SensorEvent event) {
float x = event.values[0];
float y = event.values[1];
float z = event.values[2];
//Check time interval, not sure if this is correct though.
long actualTime = System.currentTimeMillis();
if ((actualTime - lastUpdate) > 100) {
long diffTime = (actualTime - lastUpdate);
lastUpdate = actualTime;
//This is where the magic should happen
}
}
I guess the main question is, how do I detect vibrations? Almost all other examples on the net is about how to detect shakes and movement.
Real answer- you're going to need to study DSP to get good results. This is a non-trivial problem.
Quick overview- when a vibration occurs, you're going to see a sinusoidal attenuating wave pattern (the attenuating signal after the main vibration is called "ringing" and is a bad thing for us- it means we need to separate ringing from real results). This can be detected and a vibration signalled based on looking for rapid changes in amplitude on the downwards vector (whichever one has gravity on it at the moment). The relative heights of the peak of the waves should be the relative strength of the knock.
So detecting one knock is fairly easy. Things that aren't easy:
*Telling the difference between a knock and footsteps across the room- both cause vibrations. They'll look the same. You may be able to filter it out via frequency analysis and filters
*Telling two knocks vs one knock in a short time frame. The second knock tends to be weaker, and will be difficult to tell apart form the ringing of the first knock. It may also have destructive interference with the first wave.
*Telling exactly when a knock occurred. There will be a time delay that may not be constant, and trying to figure it out means trying to find an exact peak. Difficult to do with noise.
*Telling a knock in a noisy environment (vibrationally noisy, not sound). Again, you'll need filtering.
I've actually done this, somewhat. And failed mostly I think. We were able to detect knocks well, but not to filter out noise at all. Of course we were looking for extremely small (1 finger) knocks, if you're looking for sharp raps you'll have fewer problems as the spike will be larger compared to the noise level. If you're expecting a single sharp knock the basics of looking for large spikes and ignoring secondary spikes for N milliseconds afterwards may be enough for you. If it isn't you're going to spend a lot of time on this.

Sony SmartWatch2 Accelerometer sends bad values

I have built and installed HelloSensor sample app on my Android/SmartWatch2 devices.
After commenting //sensor.getType().getName().equals(Registration.SensorTypeValue.MAGNETIC_FIELD)
to avoid accelerometer values display to be scratched by magnetic field values display, I was very happy with the result: I clearly saw the expression of "SW2 acceleration - gravity" displayed on my SmartWatch (clearly seeing ~(0, 0, 9.8) when the watch is layed down on a table, and ~(0, 9.8, 0) when I hold the SW vertically).
My problem is that, today, whatever orientation I give to my SmartWatch, values do not change anymore => ~(0, 0, 9.8) is always displayed, even if I hold the SW vertically.
Since it worked fine at first, I wonder if my sensor is not "broken". How can I check this?
Did you try restarting and/or resetting your SW2? Also you can try unpairing/repairing the watch with the phone.
If it still isn't working, not sure there is much you can do to check the sensor otherwise. If your watch is still under warranty would suggest sending it in for repairs.

Is this a Digital Compass or Unity limitation?

I'm interested in AR applications of mobile devices and naturally I would like to make better use of the compass.
The only issue I've been having to work against isn't how twitchy the compass is. (Angular Smoothing seems to solve this issue just fine) My main issue is that when the device is held Vertical the compass values start freaking out. Causing an on screen compass to flip about all over the place. I don't have a lot of experience with mobile application development so I'm not sure what would be causing this issue, if its a Unity issue or if its just a limitation of the digital compass. I know other apps do seem to be able to use the compass fine in any orientation, but this is all stupidly new to me.
I've definitely tried moving the phone in a figure of 8. The device I have to play around with is a Nexus 4.
using UnityEngine;
using System.Collections;
public class Compass : MonoBehaviour {
// Use this for initialization
void Start () {
Input.location.Start ();
Input.compass.enabled = true;
}
// Update is called once per frame
void Update ()
{
var heading = Input.compass.trueHeading;
transform.eulerAngles = new Vector3 (0, 0, heading);
}
}
Preamble :)
First of, I'm not an expert (unfortunately) in subjects that I will talk about. But still, I've decided to share my thoughts.
Theory
The problem can be generalized in the following way. You want to have some continuous function that takes a 3D vector (which is device orientation in your case) and returns another vector that is orthogonal to original vector. Theory says (see hairy ball theorem) that for some arguments that function will return zero vectors. In case when such a function is compass, zero vectors are returned when device is oriented vertical (and this fells quite natural if you have ever used an ordinary compass).
Practice
Sometimes you want your app to tell which side of the world does phone back (rear camera) is pointing to.
Or maybe even you want combined approach:
If the phone is oriented flat, show what is the phone's top pointing to.
If the phone is oriented vertical, show what is the phone's back pointing to.
In both cases you need to use gyroscope in addition to compass.

Gyroscope does not show any drift

I'm in a little bit weird situation. The situation I currently have is typically a good one - no gyro drift at all - but I have no clue why this is the case. I expected the gyroscope to drift a lot as reported everywhere. Therefore this question to find the reason why I do not see any drift.
I use a Galaxy Nexus (Android 4.0.3) and its gyroscope to do some orientation change detection in the end. In the first place, I just wanted to log the sensor readings and expected to see large drifting values as for example here. Also on other websites I read of drifting of about 1 degree per second or similar measurements.
My code to log the sensor data is very basic:
SensorManager sm = (SensorManager) getSystemService(SENSOR_SERVICE);
LogSensorEventListener listener = new LogSensorEventListener(
SensorLoggerActivity.this, Sensor.TYPE_GYROSCOPE);
sm.registerListener(listener, sm.getDefaultSensor(Sensor.TYPE_GYROSCOPE),
SensorManager.SENSOR_DELAY_FASTEST);
LogSensorEventListener is also a very basic implementation of the SensorEventListenerInterface:
#Override
public void onSensorChanged(SensorEvent event) {
final float dT = (event.timestamp - mTimestamp) / 1000000000.f;
if (dT < 1) { // just a fix for the first step
mRelZ += event.values[2] * dT;
list.add(mRelZ);
list2.add(event.timestamp);
}
mTimestamp = event.timestamp;
mRelZ is initially set to 0 and the two lists should keep track of time and measured value. If finished with my measurement (clicking a button) the values are written to file:
try {
for (int i = 0; i < list.size(); i++) {
long time = list2.get(i);
if (mStartTime < 0) {
mStartTime = time;
time = 0;
} else {
time = time - mStartTime;
}
float timef = time / 1000000000.0f;
sb.append(timef);
sb.append(";");
sb.append(Math.toDegrees(list.get(i)));
sb.append("\n");
}
mOutFileStream.write(sb.toString().getBytes());
mOutFileStream.flush();
mOutFileStream.close();
} catch (IOException e) {
}
Everything works fine but the only drift I can see (for example when having the device lying on a table and logging values for let's say 60 seconds) is about 0.2 degree.
If I move the device to get something like in the screenshot above no drift can be observed at all...
What I'm I doing wrong (or right?)??
Thanks for any advice!
the gyro you have might be a post-filtered one, i found this in some of the SAMSUNG I9100 devices. they use gyros produced by INVENSENSE CORP.
edit 2014/12/10 for commenting #Lourenço Castro
i believe #Lourenço Castro was right about the 'factory drift'(or zero-drift) and 'accumulated drift';
Concerning to complementary/kalman filters, on Android, the 6dof(ACC+GYRO) impl. works fine, it can remove both factory and accumulated drift of gyroscope thanks to accelerometer's calibration;
However, the 9dof impl., or adding a magnetometer sensor into consideration, filter runs into status you dont want. According to my tests, it is caused by uncalibed status of magnetometer which need guys to shake (known as drawing 'eight')the phone to remove before fusion.
9dof provides a full rotation estimation while 6dof can not handle the accumulated drift of rotating around y axis(see android's ref. for axis definition). And I dont think that 'shaking-and-drawing-number-8' before one starts an app is a good UE, so we have to go back to 6dof method and try to find a way to remove factory drift of rotation around y-axis.
(a lot of boring but amazing content about complementary/kalman filter should be here. but i guess those come here already know it.)
You can try a 360 panorama app included in Google Camera which can be downloaded from market. This app use a visual-aid(image processing based motion estimation) for calibrating the sensor before we really start to capturing, it's easy to verify this. And no use of Magnetometer, i guess.
So my advice to use sensor-fusion on Android is:
1. no magnetometer; (dont know if this is a hardware problem or can be solved by software.)
2. accelerometer+gyroscope provides smooth and stable 6dof motion estimation;
3. try to solve the drift around y-axis, mainly means that visual-method should be added to;
4. try 3 and try 3...
Maybe someone will run into this question and i hope all above might be helpful.
thanks to those posts related to this questions on StackOverflow.
i dont remember your names exactly but you all helped me a lot. :)
I was browsing for this subject and, although this is an old question, I don't believe the accepted answer is correct.
The drift that is "reported everywhere" is caused by the integration of noisy gyroscope data (as seen on the link provided by the O.P.), not by simply outputting the sensor data. You will need this integration to calculate orientation changes over time.
Longer integration periods will contain larger noise amounts which will accumulate drift fairly quickly. I believe the internal filtering of the signal which happens on Invensense hardware is used to remove drift caused by their own pre-processing of the gyroscope.
In Android's case, in API 18 (Jelly Bean MR2), a GYROSCOPE_UNCALIBRATED sensor was added, in which you can (presumably) verify this factory drift calibration. Anyway, when you try to integrate either the calibrated and uncalibrated sensor events, you will get drift, since both are pretty noisy. To reduce this issue you will have to delve into complementary or Kalman filters.
(Sorry about not posting more informational links, not enough reputation).
Hope this helps future users.

How can I find the velocity using accelerometers only?

Using only the phone's (Android) built in accelerometer, how would I go about finding its velocity?
I have been tinkering with the maths of this but whatever function I come up with tends to lead to exponential growth of the velocity. I am working from the assumption that on startup of the App, the phone is at a standstill. This should definitely make finding the velocity (at least roughly) possible.
I have a decent background in physics and math too, so I shouldn't have any difficulty with any concepts here.
How should I do it?
That will really depend on what the acceleration is and for how long. A mild, long acceleration could be measurable, but any sudden increase in acceleration, followed by a constant velocity, will make your measurements quite difficult and prone to error.
Assuming constant acceleration, the formula is extremely simple: a = (V1-V0)/t . So, knowing the time and the acceleration, and assuming V0 = 0, then V1 = a*t
In a more real world, you probably won't have a constant acceleration, so you should calculate Delta V for each measurement, and adding all those changes in velocity to get the final velocity. Always consider that you won't have a continuous acceleration data, so this is the most feasible way (i.e, real data vs integral math theory).
In any way, even in the best scenario, you will end up with a very high error margin, so I do not recommend this approach for any app that truly depends on real velocities.
First, you have to remove the acceleration due to gravity from the accelerometer data. Then it's just a matter of integrating the acceleration to get the velocity. Don't forget that acceleration and velocity are properly vectors, not scalars, and that you will also have to track rotation of the phone in space to properly determine the orientation of the acceleration vector with respect to the calculated velocity vector.
There is nothing else to do but agree with the reasonable arguments put forward in all the great answers above, however if you are the pragmatic type like me, I need to come up with a solution that works somehow.
I suffered a similar problem to yours and I decided to make my own solution after not finding any on-line. I only needed a simple "tilt" input for controlling a game so this solution will probably NOT work for more complex needs, however I decided to share it in case others where looking for something similar.
NOTE: I have pasted my entire code here, and it is free to use for any purpose.
Basically what I do in my code is to look for accelerometer sensor. If not found, tilt feedback will be disabled. If accelerometer sensor is present, I look for magnetic field sensor, and if it is present, I get my tilt angle the recommended way by combining accelerometer and magnetic field data.
public TiltSensor(Context c) {
man = (SensorManager) c.getSystemService(Context.SENSOR_SERVICE);
mag_sensor = man.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
acc_sensor = man.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
has_mag = man.registerListener(this, mag_sensor, delay);
has_acc = man.registerListener(this, acc_sensor, delay);
if (has_acc) {
tiltAvailble = true;
if (has_mag) {
Log.d("TiltCalc", "Using accelerometer + compass.");
}
else {
Log.d("TiltCalc", "Using only accelerometer.");
}
}
else {
tiltAvailble = false;
Log.d("TiltCalc", "No acceptable hardware found, tilt not available.");
//No use in having listeners registered
pause();
}
}
If however only the accelerometer sensor was present, I fall back to accumulating the acceleration, that is continuously damped (multiplied by 0.99) to remove any drift. For my simple tilt needs this works great.
#Override
public void onSensorChanged(SensorEvent e) {
final float[] vals = e.values;
final int type = e.sensor.getType();
switch (type) {
case (Sensor.TYPE_ACCELEROMETER): {
needsRecalc = true;
if (!has_mag) {
System.arraycopy(accelerometer, 0, old_acc, 0, 3);
}
System.arraycopy(vals, 0, accelerometer, 0, 3);
if (!has_mag) {
for (int i = 0; i < 3; i++) {
//Accumulate changes
final float sensitivity = 0.08f;
dampened_acc[i] += (accelerometer[i] - old_acc[i]) * sensitivity;
//Even out drift over time
dampened_acc[i] *= 0.99;
}
}
}
break;
case (Sensor.TYPE_MAGNETIC_FIELD): {
needsRecalc = true;
System.arraycopy(vals, 0, magnetic_field, 0, 3);
}
break;
}
}
In conclusion I will just repeat that this is probably not "correct" in any way, it simply works as a simple input to a game. To use this code I simply do something like the following (yes magic constants are bad mkay):
Ship ship = mShipLayer.getShip();
mTiltSensor.getTilt(vals);
float deltaY = -vals[1] * 2;//1 is the index of the axis we are after
float offset = ((deltaY - (deltaY / 1.5f)));
if (null != ship) {
ship.setOffset(offset);
}
Enjoi!
Integrating acceleration to get velocity is an unstable problem and your error will diverge after a couple of seconds or so. Phone accelerometers are also not very accurate, which doesn't help, and some of them don't allow you to distinguish between tilt and translation easily, in which case you're really in trouble.
The accelerometers in a phone are pretty much useless for such a task. You need highly accurate accelerometers with very low drift - something which is way beyond what you will find in a phone. At best you might get useful results for a few seconds, or if very lucky for a minute or two after which the results become meaningless.
Also, you need to have a three axis gyroscope which you would use to integrate the velocity in the right direction. Some phones have gyros, but they are even poorer than the accelerometers as far as drift and accuracy are concerned.
One possibly useful application though would be to use the accelerometers in conjunction with gyros or the magnetic compass to fill in for missing data from the GPS. Each time the GPS gives a good fix one would reset the initial conditions of position, speed and orientation and the accelerometers would provide the data until the next valid GPS fix.
Gravity is going to destroy all of your measurements. The phone, at standstill, is experiencing a high constant upward (yes, UP) acceleration. An accelerometer can't distinguish between acceleration and gravity (technically, they are the same), so it would get to extremely high velocities after a few seconds.
If you never tilt your accelerometer even slightly, then you can simply subtract the constant gravitional pull from the z-axis (or whichever axis is pointing up/down), but thats quite unlikely.
Basically, you have to use a complicated system of a gyroscope/magnetometor and an accelerometer to calculate the exact direction of gravity and then subtract the acceleration.
v = Integral(a) ?
Generally though, I'd think the inaccuracies in the accelerometers would make this quite tough
If the phone is at standstil, you have ZERO acceleration, so your speed is 0. Probably you should find location data from GPS and get the associated time samples and compute velocity distance over time.

Categories

Resources