Accoprding to this: http://developer.android.com/guide/topics/sensors/sensors_motion.html
In modern Android devices you can measure 1) acceleration (including gravity), 2) linear acceleration (excluding gravity), 3) gravitational acceleration, all along the X,Y,Z axes.
Is the linear acceleration reading simply the accelerometer reading - gravity reading? Or differently put, is the accelerometer equal to the linear acceleration + gravitational acceleration? I.e., there are 9 different data points being sensed, and I'm trying to figure out whether three are redundant.
As far as I remember, there is a single hardware sensor for acceleration (apart from gyroscope, which measures angular acceleration).
Gravity is a "fake" sensor, which value is extracted from the raw acceleration by a low-pass filter.
Linear acceleration is, indeed, just the difference.
As #mstrthealias pointed out, even if this is redundant, it might be more efficient to directly get the linear acceleration rather than compute the difference in Java, but I'm just speculating here.
Related
I'm recording the following sensor values from my tablet (given as constants of the Sensor class):
TYPE_ACCELEROMETER
TYPE_GRAVITY
TYPE_GYROSCOPE
TYPE_LIGHT
TYPE_LINEAR_ACCELERATION
TYPE_MAGNETIC_FIELD
TYPE_ROTATION_VECTOR
The problem is that I'm producing too much data. That's why I want to use less sensors. I think some sensors are redundant, i.e. can be computed from other sensor values. For example I think linear acceleration and gravity will give accelerometer and perhaps the rotation vector can be computed from linear acceleration and gyroscope (how?).
Which sensors are redundant? I'm guessing that accelerometer (or linear acceleration) as well as the rotation vector are redundant. Moreover, can the magnetic field be used for the computation of other measures (like the rotation vector)? I don't need the magnetic field value on its own, so perhaps I can also throw it out.
Edit: I think it holds that accelerometer = gravity + linear acceleration. Does this mean that gravity and linear acceleration correlates with the accelerometer? Correlated features would be useless as input to my machine learning pipeline.
I guess that rotation vector is computed with the help of the magnetic field but my magnetic field sensor has low accuracy (reported by Android), so I could drop magnetic field as well as rotation vector.
I am working on an android app that requires the detection of vertical motion. When moving the tablet upward, the Gyroscope, Accelerometer, and Linear Acceleration sensors give a corresponding value indicating upward or downward motion.
The problem I have is that these sensors will also read an upward/downward motion when you tilt the tablet towards the user or away from the user. For example, the x value in the gyroscope represents the vertical plane. But when you tilt the device forwards, the x value will change.
When I make this motion, the same sensor that reads vertical motion reads a value for this.
The same goes for the rest of the sensors. I have tried to use orientation coupled with the gyro to make the conditional statement, if the pitch is not changing, but the x variable is going up/down, then we have vertical motion. The problem with this is that if the user moves it up but tilted slightly, it will no longer work. I also tried making it so if there is a change in tilt, then there is no vertical motion. But it iterates so quickly that there may be a change in tilt for 1/100 of a second, but for the next there isn't.
Is there any way I can read only vertical changes and not changes in the devices pitch?
Here is what I want to detect:
edit:
"Please come up with a mathematically sound definition of what you consider 'moving upwards.'"
This was my initial question, how can I write a function to define when the tablet is moving upwards or downwards? I consider a vertical translation moving upwards. Now how do I detect this? I simply do not know where to begin, thank you.
Ok, even though this question is fairly old, I see a lot of confusion in the present answer and comments, so in case anyone finds this, I intend to clear a few things up.
The Gyroscope
First of all, the gyroscope does not measure vertical motion as per your definition (a translatory motion). It measures rotation around each of the axes, which are defined as in the figure below. Thus having you tilt your device forwards and backwards indeed rotates it around the x axis and therefore you will see non-zero values in the x value of your gyroscope sensor.
the x value in the gyroscope represents the vertical plane.
I'm not sure what is meant by "the vertical plane", however the x value certainly does not represent the plane itself nor the orientation of the device within the plane.
The x value of the gyroscope sensor represents the current angular velocity of the device around the x axis (eg. the change in rotation).
But when you tilt the device forwards, the x value will change. When I make this motion, the same sensor that reads vertical motion reads a value for this.
Not quite sure what you're referring to here. "The same sensor that reads vertical motion" I assume is the gyroscope, but as previously said, it does not read vertical motion. It does exactly what it says on the tin.
The device coordinate system
This is more in response to user Ali's answer than the original question, but it remains relevant in either case.
The individual outputs of the linear acceleration sensor (or any other sensor for that matter) are expressed in the coordinate system of the device, as shown in the image above. This means if you rotate the device slightly, the outputs will no longer be parallel to any world axis they coincided with before. As such, you will either have to enforce that the device is in a particular orientation for your application, or take the new orientation into account.
The ROTATION_VECTOR sensor, combined with quaternion math or the getRotationMatrixFromVector() method, is one way to translate your measurements from device coordinates to world coordinates. There are other ways to achieve the same goal, but once achieved, the way you hold your device won't matter for measuring vertical motion.
In either case, the axis you're looking for is the y axis, not the z axis.
(If by any chance you meant "along device y axis" as "vertical", then just ignore all the orientation stuff and just use the linear acceleration sensor)
Noise
You mentioned some problems regarding noise and update rates in the question, so I'll just mention it here. The simplest and one of the more common ways to get nice, consistent data from something that varies very often is to use a low-pass filter. What type of filter is best depends on the application, but I find that a exponential moving average filter is viable in most cases.
Finishing thoughts
Note that if you take proper care of the orientation, your transformed linear acceleration output will be a good approximation of vertical motion (well, change in motion) without filtering any noise.
Also, if you want to measure vertical "motion", as in velocity, you need to integrate the accelerometer output. For various reasons, this doesn't really turn out too well in most cases, although it is less severe in the case of velocity rather than trying to measure position.
OK, I suspect it is only a partial answer.
If you want to detect vertical movement, you only need linear acceleration, the device orientation doesn't matter. See
iOS - How to tell if device is raised/dropped (CoreMotion)
or
how to calculate phone's movement in the vertical direction from rest?
For some reason you are concerned with the device orientation as well, and I have no idea why. I suspect that you want to detect something else. So please tell us more and then I will improve my answer.
UPDATE
I read the post on coremotion, and you mentioned that higher z lower x and y means vertical motion, can you elaborate?
I will write in pseudo code. You measured the (x, y, z) linear acceleration vector. Compute
rel_z = z/sqrt(x^2+y^2+z^2+1.0e-6)
If rel_z > 0.9 then the acceleration towards the z direction dominates (vertical motion). Note that the constant 0.9 is arbitrary and may require tweaking (should be a positive number less than 1). The 1.0e-6 is there to avoid accidental division by zero.
You may have to add another constraint that z is sufficiently large. I don't know your device, whether it measures gravity as 1 or 9.81. I assume it measures it as 1.
So all in all:
if (rel_z > 0.9 && abs(z) > 0.1) { // we have vertical movement
Again, the constant 0.1 is arbitrary and may require tweaking. It should be positive.
UPDATE 2
I do not want this because rotating it towards me is not moving it upwards
It is moving upwards: The center of mass is moving upwards. My code has the correct behavior.
Please come up with a mathematically sound definition of what you consider "moving upwards."
What is the difference between gravity and acceleration sensors in Android? From my point of view the physical value is the same in both cases.
Which one measures the force acting on unit mass inside the device?
ADDITION
The question is: what physical quantity is measured by these sensors? According to equivalence principle the acceleration and gravity are indistinguishable and the only way to measure both is by usual (but 3d) spring balance.
Acceleration sensor gives you back the sum of all forces applied to your device, while Gravity sensor returns only the influence of gravity. If you want to exclude the gravity from acceleration, you may use a high-pass filter or just subtract the gravity sensor values from acceleration sensor values -- not sure which method gives better precision.
Another method could be using Sensor.TYPE_LINEAR_ACCELERATION, which gives exactly (acceleration - gravity), however you should check if it's available on the device. I've found a few devices, which have ACCELERATION sensor working, but no response from GRAVITY or LINEAR_ACCELERATION sensors.
This link might be helpful: http://www.sensorplatforms.com/which-sensors-in-android-gets-direct-input-what-are-virtual-sensors
The following excerpt summarize the answer for your question:
"The list... includes both physical sensors and sensor types with values derived from physical sensors, sometimes these are called virtual sensors... The virtual sensors types (gravity, linear acceleration, and rotation vector) provide values derived by combining the results from physical sensors intelligently... The rotation vector is a combination of the accelerometer, the magnetometer, and sometimes the gyroscope to determine the three-dimensional angle along which the Android device lays with respect to the Earth frame coordinates. By knowing the rotation vector of a device, accelerometer data can be separated into gravity and linear acceleration."
This link https://stackoverflow.com/a/8238389/604964 also says that the gravity values are computed using a Butterworth filter.
In Android Documentation is specified the third parameter as
float[] gravity
then is specifies
[0 0 g] = R * gravity (g = magnitude of gravity)
Now, in most of the examples online I can see everyone sending accelerometer values to getRotationMatrix, but, Isn't suppose that I should send only gravity values?
For example, if the mobile phone has the gravity sensor,
Should I send it raw output to getRotationMatrix?
If it hasn't one, Should I send accelerometer values? Should I extract non gravity components first? (as accelerometer values are Acceleration minus G).
Will the use of gravity sensor values be more reliable than using accelerometer values in mobile phones that have that sensor?
Thanks in advance! Guillermo.
I think the reason you only see examples using the accelerometer values is because the gravity sensor was only launched in API 9 and also because most phones might not give this values separated from the accelerometer values, or dont have the sensor, etc, etc..
Another reason would be because in most of the cases the result tend to be the same, since what the accelerometer sensor outputs is the device linear acceleration plus gravity, but most of the time the phone will be standing still or even moving at a constant velocity, thus the device acceleration will be zero.
From the setRotationMatrix Android Docs:
The matrices returned by this function are meaningful only when the device is not free-falling and it is not close to the magnetic north. If the device is accelerating, or placed into a strong magnetic field, the returned matrices may be inaccurate.
Now, you're asking if the gravity data would me more reliable? Well, there is nothing like testing, but I suppose it wouldn't make much difference and it really depends on which application you want. Also, obtaining the simple gravity values is not trivial and it requires filtering, so you could end up with noisy results.
I am developing an app using android OS for which I need to know how can I calculate the movement of the device up in the vertical direction.
For example, the device is at rest (point A), the user picks it up in his hand (point B), now there is a height change between point A and point B, how would i calculate that?
I have already gone through the articles about sensors and accelerometers, but I couldn't really find anything to help me with that. Anyone have any ideas?
If you integrate the acceleration twice you get position but the error is horrible. It is useless in practice. Here is an explanation why (Google Tech Talk) at 23:20. I highly recommend this video.
Now, you do not need anything accurate and that is a different story. The linear acceleration is available after sensor fusion, as described in the video. See Sensor.TYPE_LINEAR_ACCELERATION at SensorEvent. I would first try a high-pass filter to detect sudden increase in the linear acceleration along the vertical axis.
I have no idea whether it is good for your application.
You can actually establish (only) the vertical position without measuring acceleration over time. This is accomplished by measuring the angle between the direction to the center of the earth, and the direction to the magnetic north pole.
This only changes (significantly) when the altitude (height) of the phone changes. What you do is use the accelerometer and magnetometer to get two float[3] arrays, treat these as vectors, make them unit vectors, and then the angle between any two unit vectors is arccos(AxM).
Note that's dot product ie. math.acos(A[0]*B[0]+A[1]*B[1]+A[2]*B[2]) Any change in this angle corresponds to a change in height. Also note that this will have to be calibrated to real units and the ratio of change in angle to height will be different at various longitudes; But this is a method of getting an absolute value for height; though of course the angle also becomes skewed when undergoing acceleration, or when there are nearby magnets :)
you can correlate it to magnetic field sensor in microTesla
You can use dist= integral of integral of acceleration ~ sigma ~ summation
= integral of speed+constant