I am trying to write an app that needs to be able to tell if a vehicle is accelerating or breaking. In this sense I used the accelerometer in the phone. At the moment I managed to isolate and subtract the gravitational pull of the earth from my readings and I am using a noise variable to ignore minor changes (smaller than 10^-2).
In order to compute the acceleration relative to the ground I am using the following formula sqrt(Lx^2+Ly^2+Lz^2), where Lx represents the linear acceleration along the x-Axis in m/s^2.
My problem is: How do I differentiate between braking and accelerating, as my final acceleration value will always be greater than 0. Also I need this to work even if the vehicle accelerates -> maintains speed -> brakes/accelerates some more. Is my reasoning wrong? Have I made some false assumptions? Would another way be better? The phone I am using for development also has a gravity sensor and a gyroscope.
Related
I am creating app that will measure acceleration of vehicle in each axis using accelerometer in Android smartphone. I need somehow rotate phone measurement coordinations system to coordination system of vehicle - to allow driver to put phone in holder - and so phone will have some different rotation to vehicle.
I started with calibration process where I tell user to hold phone to match vehicle coordination system - so I save TYPE_GRAVITY sensor X, Y, and Z gravity acceleration value. Then I tell user to put phone in holder and again save TYPE_GRAVITY sensor X, Y, and Z gravity acceleration value.
Now I need to find some relation between those two vectors so I can use it to correct (rotate) TYPE_LINEAR_ACCELERATION X,Y,Z data to match vehicle coordinations system.
Using just a gravity sensor you'll lack one rotational axis to compute what you want.
Imagine your phone being held vertically, the accelerometer will show you direction to the bottom of the phone. If you now rotate it around vertical axis - you'll still get the same result from the accelerometer. This means you can't get the rotation around vertical axis this way.
One solution would be to use a gyroscope - this gives you entire rotation of the phone, but increases a hardware requirements of your app.
But the better solution IMHO would be to get rid of the entire calibration process. Cars move mostly straight, only sometimes you get the side way acceleration so you could scan your readings for few seconds and find a 'main' axis and a 'side' one.
Besides, your calibration process still depends on user precision during placing the phone, so it may not work as you've expected.
My goal is to have a simple stroke rate detector displayed on my Android Watch (Sony Smartwatch), for this I need to detect when the watch changes from moving forwards to moving backwards.
I have code working that will get the event values (x,y,z) as detected in the onSensorChanged event (and display them on the watch), but I am struggling to make sense of these.
I understand the values report acceleration in the given axis, and I understand that z reports gravity. But if these values are reporting just acceleration, I am not clear how to know when there is a change of direction. I presume a positive number indicates acceleration, a number of 0 is a constant speed and a negative number is deceleration...is that correct? And if so, how can I detect when the Watch has changed direction from going forwards to going backwards?
Thanks in advance.
Android Wear is no different than "conventional" Android when it comes to detecting motion. Basically, you need to consider exactly what the accelerometers are recording: raw acceleration (with a lot of noise). To determine motion from that, you need to look at trends over time, and probably integrate the smoothed accelerometer data. It's not trivial.
You'll probably want to use the TYPE_LINEAR_ACCELERATION sensor, because it filters out gravity (which isn't relevant to your use case). And because the watch will probably experience some rotation during a rowing stroke (which you want to factor out), you may need to combine TYPE_ROTATION_VECTOR with the acceleration vector to accurately determine direction changes.
A couple of other SO questions which may help point you in the right direction:
how to calculate phone's movement in the vertical direction from rest?
How can I get the direction of movement using an accelerometer?
I've not attempted this specific problem, of course, but I've done enough other work with Android motion sensors to know that you have a good programming challenge ahead of you. Enjoy it!
I'm developing a tool which receives motion sensor data and sends it to a machine learning algorithm, which ultimately will deduce different types of movement.
I read the Motion sensor guide and it seems like there is some redundancy in the data you can get from the sensors. For example: the accelrometer data contains gravity data and the linear acceleration data shows acceleration without acceleration due to gravity.
So my question is: do i really need all the sensors to get all forms of motion or can I give up some of them?
EDIT: (clarifying the question)
I want to collect the minimal data that will allow me to deduce the same things. What I'm looking for is user behavior: the angle which the user holds his phone, the way the user moves while using his phone, etc..
The answer I'm looking for should include the sets of sensors that have high correlation within them, such that only some of the sensors in this set are required to deduce the same type of motion\movement\rotation\acceleration\etc..
The term "Motion" in the question have no precise meaning. So I answer more generally.
"The way one holds his phone" is nothing but the orientation of the phone.There are three sensors which individually tells the orientation of the phone.
Accelerometer sensor
Orientation sensor
Rotation Vector sensor
Among them only the accelerometer is physical sensor and other two are virtual sensors (they don't have special piece of hardware, they use accelerometer data and report the orientation in different formats).
The orientation sensor is deprecated so you can't use it.
Rotation vector sensor tells the orientation encoded in a quaternion. If your code is based on quaternions then normalize the sensor output using SensorManager.getQuaternionFromVector() and continue. If your code is based on rotation matrix then obtain rotation matrix by calling SensorManager.getRotationMatrixFromVector() passing sensor output and continue. If you want the orientation alone get it by calling SensorManager.getOrientation() passing rotation matrix obtained previously.
Using accelerometer sensor we can find the orientation, but the recommended approach is to combine it with magnetic field sensor output. Call SensorManager.getRotationMatrix() by passing the output of accelerometer output and magnetic field sensor output and get the rotation matrix. If your code is based on rotation matrix, just continue. If you want the orientation alone get it by calling SensorManager.getOrientation() passing rotation matrix obtained in previously. If your code is based on quaternion call SensorManager.getQuaternionFromVector() by passing rotation vector (orientation) obtained previously.
"The way one moves his phone" - Here I consider four motions.
Change of position (Simple translation) and rate change of position (velocity) - No sensor to detect them.
Rate of change of velocity (Simple acceleration) - Accelerometer detects it. But it also contains the gravity component. Normally we need acceleration without gravity component. This could be calculated simply as explained here. However there is another virtual sensor called Linear Acceleration which does the job for us.
Change of orientation (Rotation) - Whenever the orientation changes the accelerometer, orientation and rotation vector sensors report us (gyroscope also reports, but is explained in next point). How to use this sensor to get the current orientation is explained in first part of the answer.
Rate of change of orientation (Angular velocity) - Whenever the orientation changes the gyroscope sensor reports. The output is three numbers representing angular acceleration along x, y and z axes. The unit is radians per second.
Output of the gyroscope sensors is not accurate in long term and the output of accelerometer is not accurate in short term, so combine them to get steady output. For details see this question.
Now it is clear that the gyroscope and accelerometer is required in minimum. However using wide range of sensors minimizes our work.
You can't decide what you get - each sensor's data is already defined, and you get all or nothing. If you see closely, there isn't a place in public API which would let you ask for specific things.
To back this up here's quote from Google's document explaining sensor types:
An accelerometer sensor reports the acceleration of the device along the 3 sensor axes. The measured acceleration includes both the physical acceleration (change of velocity) and the gravity. The measurement is reported in the x, y and z fields of sensors_event_t.acceleration.
If you see into android source, the structs here are strictly defined, and struct for acceleration contains specific fields. So even if you would get 0 in fields you don't like, you won't gain anything.
But what you're referring to are two things - base sensors, which are roughly equivalent to physical sensors on the device, and composite sensors, which combine readings from various physical sensors to get more useful data.
So while you can't decide what you get for a particular sensor (like "only gravity" or "only acceleration in Y axis"), composite sensors do give you data that you can compute by yourself using only base sensors. So linear acceleration is composition of data from accelerometer and gyroscope (or magnetic sensor), after some calculations. Similarly step detector "sensor" uses only accelerometer, but interpretes the data automatically to just give you an event that "yes, someone has made a step" with single value 1.
If you're feeding raw motion data to some algorithms, I would guess base sensors are what you're looking for. That said, I believe you can still safely register for all sensors (both base and composite ones) that combined give you all data that you need (and maybe more), without meaningful battery impact.
For more detailed information on each of the sensors refer to Sensor types on Android website, and if you're curious, you can read up short summary on sensors stack as well.
No, you don't need every sensor. Some of the sensors exist as a convenience to the user. Your example of the linear acceleration sensor is one- it tells you the results of the accelerometer with gravity taken out. You could do this yourself from the raw accelerometer data, but that takes a bit of math (you need to subtract the vector gravity over all 3 axes) and a bit of knowhow (did you remember to calibrate the sensor? It may not read 9.8 at rest. For that matter, 9.8 may not be your gravity if you're not at sea level). That's a lot of work that would need to be repeated by each app, so they created a software "sensor" that sits on top of the accelerometer and provides the computed data. It would be unusual for an app to use raw and linear accelerometers in the same app, generally its one or the other. The step counter is another example of this, it guesses at what a step is based on the accelerometer data. You also wouldn't want calibrated and uncalibrated gyroscope data.
As for what you do need- no clue, you don't say enough about what you're trying to do. One warning though- you said you're trying to detect motion. YOu can't do that. You can detect accelerations and rotation. You cannot detect motion at a constant speed. If you're developing any type of app using these it pays to use the correct terminology and think in terms of physics and how the physical accelerometer and gyroscope work, otherwise you're going to cause yourself bugs.
So, right now I'm grabbing the accelerometer data and converting them to a decently rough estimate of the angle at which the phone is being held. For right now I'm just focused on the yaw axis.
My area of interest is between 0 and 45 degrees on the yaw axis, so I made a limited queue of the past 5 to 10 readings and compared the numbers to determine if it's going up or down, which kind of works, but it is slow and not really as precise or reliable as I'd want it to be.
Is there a way you can kind of just determine which direction your phone is rotating with just the accelerometer and the magnetic field sensor I guess, without keeping a history of past readings, or something like that? I'm really new to sensor manipulation and Android in general. Any help understanding would be great.
It's not clear exactly what you're looking for here, position or velocity. Generally speaking, you don't want to get a position measurement by using integration on the accelerometer data. There's a lot of error associated with that calculation.
If you literally want the "direction your phone is rotating," rather than angular position, you can actually get that directly from the gyroscope sensor, which provides rotational velocities. That would let you get the direction it's rotating from the velocity without storing data. You should be aware that not every phone has a gyroscope sensor, but it does seem like the newer ones do.
If you want the absolute orientation of the phone (position), you can use the Rotation Vector sensor. This is a combined sensor that automatically integrates data from several of the sensors in one go, and provides additional accuracy. From this, you can get roll-pitch-yaw with a single measurement. Basically, you first want to get your data from the Rotation_vector sensor. Then you use the sensor data with getRotationMatrixFromVector. You can use the output from that in getOrientation (see the same page as the previous link), which will spit out roll-pitch-yaw measurements for you. You might need to rotate the axes around a bit to get the angles measured positive in the direction you want.
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....