Vertical movement sensor
Asked Answered
S

2

6

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. enter image description here

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: enter image description here

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.

Sprocket answered 2/11, 2012 at 19:27 Comment(9)
When a user tilts the tablet, there's an upward/downward motion. If what you want is detect the movement while the tablet is held vertical, then only look for vertical movement if the tablet is tilted from 90º (+-10º or whatever the margin you want to give).Blare
But if the tablet is moved upward, but is tilted, then there will be no registered movement. Also, +-10 degrees is enough to mess with values of vertical movement. This is my last resort solution, I'd like something better and more reliable.Sprocket
I see some trig in your future. What should happen if the user tilts it 90 forward(parallel to horizon) and moves the tablet on its own vertical axis(forward/away from user)? What should happen if the tablet is "upside down" for lefties? What should happen if the tablet is held at 70 degrees, or a bit askew? All those conditions and more will affect "vertical" readings. Up/down movement isn't just up/down movement. It's going to take very careful design to get this working right in all/most situations.Jamnis
I too have considered some of these things. I am using this motion to control a camera, so the tablet will always face the user. I do think there is a way to do this using vectors and trig to come out with just vertical motion, I just am unable to come up with these calculations.Sprocket
You can try and calculate deltas for each axis in a given time. When the vertical axis gets an N consecutive number of bigger delta increases than the other axis, you can assume vertical movement.Blare
@Sprocket Do you want to detect the device being lifted OR do you want to detect the device being moved along one of its edges (you pick which edge)?Photoflash
I want to detect device being moved upwards and downwards. Your holding the tablet in your hands, and then you raise your hands. Then you lower your hands. This registers an initial upward movement, then a downward movement. I don't know how I can make this more clear.Sprocket
Did you ever find a good way to solve this problem?Bisulfate
@Bisulfate what about you? I am curious if it is even possibleWhinny
B
2

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.

Device Axes

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.

Billon answered 1/7, 2015 at 12:55 Comment(0)
P
1

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."

Photoflash answered 2/11, 2012 at 21:50 Comment(16)
I don't care about orientation. It's just that the linear acceleration value for moving the tablet upwards and downwards also changes when I tilt it forwards and backwards(shown in my pictures). Therefore, I cannot reliably tell when it is moved upwards or downwards because the user could be simply be tilting it forwards or backwards. I read the post on coremotion, and you mentioned that higher z lower x and y means vertical motion, can you elaborate? Also, I've read that a high pass filter may help detect sudden movements, what exactly is this and how do I apply it to acceleration? Thank youSprocket
Also, I fear that tilting forward/backward it may result in a high z value (as would moving it up/down) and thus render what you've said useless.Sprocket
I think I may have misunderstood your question about orientation. Let me explain my project: I have an ip camera, I am streaming video to a tablet. When I move the tablet, the camera moves in the same way. But if I move it up, while tilting the device, it can mess up the result because tilting changes the value that I read for upward movement. I only want upward movement. I do not want a slight tilt changing my value. I don't want changes in pitch to affect my numbers.Sprocket
@Sprocket OK, I updated the answer. It will require some tweaking but it should work.Photoflash
As a test I did this: float rel_z = (float) (z/Math.sqrt(xx+ yy+z*z+1.0e-6)); and the value comes to be around .57. x,y,z all come from linear acceleration sensor. rel_z never really changes except from negative to positive and a few decimals in the thousandths. I am leaving work now, but I'd like to continue this if I can on monday. I did this in a hurry so I may have made a mistake somewhere, but I don't think so. Thanks.Sprocket
I dont know how I can get in contact with you, but please contact me if you can. My email is [email protected].Sprocket
@Sprocket Unfortunately, I have never done any Android programming so I am really sorry but I cannot help you with your code. :( If you wish to contact me, just leave a comment here at StackOverflow. If I am near my computer, I will notice your comment.Photoflash
Okay, after testing your code, I've found that it when I rotate the tablet towards me, the value of z increases. I do not want this because rotating it towards me is not moving it upwards. This was supposed to detect vertical motion after all, but it still has the same problem as before. Therefore your code does not help me. Is there anything else I can do?Sprocket
@Sprocket "I've found that it when I rotate the tablet towards me, the value of z increases." Correct, the center of mass is moving upwards, this is the correct behavior. You can resolve this issue by excluding the situations when the device is also significantly rotating: if (rel_z > 0.9 && abs(z) > 0.1 && not_rotating_too_much) { // we have vertical movement. The problem is that you should figure out a less vague definition of what "vertical movement" is. I am afraid you cannot and you will have to settle for some heuristic and accept the fact that it sometimes breaks.Photoflash
@Sprocket So long story short, what you want is not mathematically well-defined and one can only come up with messy heuristics. By the way, did you try tweaking the 0.9 constant? Increasing it could resolve this issue.Photoflash
I desire both upward and downward movement if that helps. I also don't think I could write a piece of code that would determine whether its not rotating too much since there is a correlation between rotation and moving the device downward/upward. Is there anything else you can suggest? Also, how can I bump this thread? Tweaking .9 won't help because tilting the device generates around .9 just as moving it up does.Sprocket
@Sprocket I can come up with a heuristic for not_rotating_too_much which may (or may not!) solve this issue you are writing. But not today, it's late evening here. Do you want to implement a heuristic for not_rotating_too_much? If yes, then perhaps tomorrow evening I can give you one.Photoflash
@Sprocket I just re-read the comments right below your question: two other people are saying the same thing, there is upward movement in the situation you want to exclude. So you have to reconsider what "upward movement" is.Photoflash
Hmm, so how would I reconsider what it is? I honestly don't have a good idea of how to discern upward movement other than the gyroscope or accelerometer.Sprocket
I consider a vertical translation my definition for moving upwards. Is it possible to write the math behind detecting this?Sprocket
@Sprocket In theory, yes. How useful that would be in practice, I have no idea. The translation is never perfect, there will be slight rotations along the way so you have to allow this. But it also makes it very difficult to exclude your issue when you turn the tablet towards yourself, after all, the center of mass is moving upwards. So I can write you a heuristic for not_rotating_too_much but how useful that will be, I have no idea.Photoflash

© 2022 - 2024 — McMap. All rights reserved.