Algorithm advice for motion tracking with accelerometer - java

I'm looking to detect some basic movement gestures using real-time accelerometer data (from the phone). My problem is that I need something generally "rotation invariant".
What I mean is that if user holds the phone upside down, then does a gesture, it won't be the same signal. Given a specific orientation, I know how to compare the real-time acc data to a given "template" of a gesture.
But what about for other orientations? E.g. the user holding the phone upside down (alright, this is easy as I can do the same basic comparison treating one axis as another) or harder yet, somewhere in-between?

As soon as the acceleration values do not change (or stay within a defined range) for some time (for instance 1 sec) you could assume that the user is in a steady position and store those values. If the values go out of that range, you can subtract the previously stored values from the new ones. That is assuming that you problem is gravity, and that you mean "orientation invariant"... right?
For a very simple case, where you just need the z-axis acceleration to have a peak:
x_wanted = 0
y_wanted = 0
z_wanted = 10
Your user in a steady position, with the device tilted at 45 degrees:
x_rest = 0
y_rest = sin(45) g
z_rest = -cos(45) g
and then brings the phone towards him, i.e z-axis (phone reference) being 10:
x_phone = x_measured - x_rest = (0) - 0 = 0
y_phone = y_measured - y_rest = (sin(45)*g) - sin(45)*g = 0
x_phone = z_measured - x_rest = (-cos(45)*g + 10) - (-cos(45)*g) = 10

It sounds like your problem is a basic transformation of coordinates. The first thing I would do is blow off the Cartesian coordinates in favor of spherical coordinates. The big advantage in doing this is the spherical radius (or vector magnitude, in cartesian-speak), which will be the same regardless of the orientation of the axes. The radius is calculated
r = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2))
A very simple way to normalize the two coordinate systems is to compare the radius of each as two time-series. This should at least eliminate a lot of the cruft, and might perform as well as you need in terms of motion identification.
Now if you really want to compare the motions in all directions, maybe after you've already found a candidate based on the radius time-series, look at Euler angles. You'll have to do some multivariate regression, but with three channels of data, three governing equations, three unknowns (alpha, beta, and gamma), and linear algebra, you can normalize all three channels in an unknown orientation back to your template orientation, and compare each channel individually.

Related

combined velocity is larger than initial velocity

I'm making a billiards game in Java. I used this guide for collision resolution. During testing, I noticed that there is more velocity between the two collided pool balls after collision. The amount of extra velocity seems to be 0%-50%. About 0% on a straight shot and 50% on an extremely wide shot. I assumed that the combined velocities would remain the same. Is it my code or my understanding of physics that is wrong?
private void solveCollision(PoolBall b1, PoolBall b2) {
System.out.println(b1.getMagnitude() + b2.getMagnitude());
// vector tangent to collision point
float vTangX = b2.getY() - b1.getY();
float vTangY = -(b2.getX() - b1.getX());
// normalize tangent vector
float mag = (float) (Math.sqrt((vTangX * vTangX) + (vTangY * vTangY)));
vTangX /= mag;
vTangY /= mag;
// get new vector based on velocity of circle being collided with
float NVX1 = b1.getVector().get(0) - b2.getVector().get(0);
float NVY1 = b1.getVector().get(1) - b2.getVector().get(1);
// dot product
float dot = (NVX1 * vTangX) + (NVY1 * vTangY);
// adjust length of tangent vector
vTangX *= dot;
vTangY *= dot;
// velocity component perpendicular to tangent
float vPerpX = NVX1 - vTangX;
float vPerpY = NVY1 - vTangY;
// apply vector to pool balls
b1.setVector(b1.getVector().get(0) - vPerpX, b1.getVector().get(1) - vPerpY);
b2.setVector(b2.getVector().get(0) + vPerpX, b2.getVector().get(1) + vPerpY);
System.out.println(b1.getMagnitude() + b2.getMagnitude());
}
Not all of this explanation will be strictly on topic, and I will assume minimal foreknowledge to accommodate potential future users - unfortunately some may consequently find it pedantic.
Velocity is not a conserved quantity and therefore the magnitude-sum of velocities before a collision is not necessarily equal to the magnitude-sum of velocities after.
This is more intuitive for inelastic collisions, particularly when you consider a scenario such as an asteroid colliding with Earth's moon1, where a typical impact velocity is on the order of 10 - 20 kilometers per second. If scalar velocity was conserved in this case - even at a 'wide' impact angle of 45° (the most probable) - the resulting velocity for the moon would be sufficient to eject it from Earth's orbit.
So clearly scalar velocity is not necessarily conserved for an inelastic collision. Elastic collisions are less intuitive.
This - as you've noted - is because there is a scenario where scalar velocity in a perfectly elastic collision is conserved (a straight-on collision), while inelastic collisions never conserve velocity2. This creates an unacceptable incongruence.
To rectify this, we have to treat velocity as a vector instead of a scalar. Consider the simplest elastic collision between two balls: one ball at rest and the second ball striking the first 'straight-on' (impact angle of 90°). The second ball will come to rest and the first will leave the collision with velocity equal to the second's initial velocity. Velocity is conserved - the magnitude-sum of velocities before and after are equal - all is well.
This will not, however, be the case for impact angles other than 90° because the magnitude sum fails to account for vector components canceling out. Say for example you have one ball again at rest and the second ball striking it at 45°. Both balls will then leave the collision at 45° angles from the second ball's initial direction of travel3. The two balls will then also have the same velocity component parallel to the initial direction of motion, and equal but opposite perpendicular velocity components. When you take a vector sum the two perpendicular components will cancel and the sum of the two parallel components will recover the initial velocity vector. However, the magnitude of each ball's resulting velocity vector will be larger than the magnitude of the second ball's initial velocity - because the magnitude is calculated by a sum of squared values and therefore does not account for opposing components.
Of course the best approach is not to look at the velocity but at the momentum - it is the conservation of momentum which governs the behaviors outlined above and in terms of momentum the explanation is very simple: it dictates that in a perfectly elastic collision the velocity of the center of mass must not change.
1 The bigger one - since Earth recently captured a second true satellite.
2 This is, in fact, part of the definition of an inelastic collision.
3 For additional background on calculating angles of departure see here.

calculate actual distance travelled by mobile [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I want to calculate actual distance traveled by mobile (iOS and Android). I know through google map API, we can find optimum route distance between 2 coordinates. But I want to calculate distance, actual path mobile(in vehicle) has covered.
One Algo I came to know is saving coordinates after x seconds, lets say after 5 or 10 seconds, and then calculate distance between consecutive coordinates, and there sum will give total distance.
I want to discuss better approach of its solution , Is there any better solution?
Edit : How Apps like Nike running app and Uber works?
------------------UPDATE----------------------
There is two major point in your question.
1) get the phone coordinates (which has been treated in the first part of this response)
2) Calculate the real distance between this two coordinates
IMHO, calculus could be done by a web service: calculation based only
on the distance between two coordinates can lead to really wrong result.
Here is an exemple of such a web service
https://graphhopper.com/#directions-api
The demo app: https://graphhopper.com/api/1/examples/
It's based on traffic flow (as many of this tools)
So you have to be careful with the order of the coordinates
because it can bring wrong result.
For exemple with two point in the right order:
This gives a good result
But if you give wrong order (with the same coordinates)
For the same coordinates, it can lead to an extremely different result.
So for coordinates ABCD (in chrnological order)
you need to do:
A->B B->C C->D
Graphhopper seems able to do offline distance calculus
Here are the lib on iOS and Android
https://github.com/graphhopper/graphhopper-ios/
https://github.com/graphhopper/graphhopper/tree/master/android
---------------------------------------------------
You have to define how your app work. Foreground or background?
As said in other responses, you'll have to get the user position every X seconds. Then calculate the distance.
For iOS:
You can use information on this website: http://mobileoop.com/
It talks about tracking user location on iOS when the app is in background.
Here is the github: https://github.com/voyage11/Location
Then you have to convert the point thanks to
CLLocationDistance distance = [aCLLocationA distanceFromLocation:aCLLocationB];
You can also check this (from apple doc) https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/LocationAwarenessPG/CoreLocation/CoreLocation.html:
Make sure the location manager’s pausesLocationUpdatesAutomatically property is set to YES. When this property is set to YES, Core Location pauses location updates (and powers down the location hardware) whenever it makes sense to do so, such as when the user is unlikely to be moving anyway. (Core Location also pauses updates when it can’t obtain a location fix.)
Assign an appropriate value to the location manager’s activityType property. The value in this property helps the location manager determine when it is safe to pause location updates. For an app that provides turn-by-turn automobile navigation, setting the property to CLActivityTypeAutomotiveNavigation causes the location manager to pause events only when the user does not move a significant distance over a period of time.
CLActivityTypeAutomotiveNavigation insure you to get a position which is on a road.
For Android:
You can use this project:
https://github.com/quentin7b/android-location-tracker
That can easily helps you to get the user's position thru time
Thanks to the TrackerSettings object
TrackerSettings settings =
new TrackerSettings()
.setUseGPS(true)
.setUseNetwork(true)
.setUsePassive(true)
.setTimeBetweenUpdates(30 * 60 * 1000)
.setMetersBetweenUpdates(100);
To find the distance between two point on Android, you can check this:
Get the distance between two geo points
Both OS
Based on a position picked up every X second you have to reduce time between picking location data to improve accuracy.
As you want to calculate distance on a road context, setup the Location manager in navigation mode, this mode gives you coordinates that are on road.
Finally
If you want to improve the accuracy of your distance calculus,
you can use a google API:
https://developers.google.com/maps/documentation/distance-matrix/intro
By setting the right mode parameter:
Optional parameters
mode (defaults to driving) — Specifies the mode of transport to use when calculating distance. Valid values and other request details are specified in the Travel Modes section of this document.
I'm working on something similar on Andoriod, but the principals are the same for iOS either:
For each GPS sample, check its accuracy. If it's over some threshold (say 20 meters) - ignore it.
Remember that even if the mobile device is static, different GPS samples will give you different locations, depending on the accuracy. A car standing still for a long time in a traffic light, will show that you've advanced few dozens of meters, so add a method that detects if the mobile is static or not. I've implemented this by reading the accelerometer - if the delta between two readings if bigger than some threshold - the device is moving. If it's too small - ignore the GPS.
If you intend to use it in a car, you can read the GPS whenever it has a new reading (in Android use the onLocationChanged method). If you use it for running/walking, take into account that your speed is slow - two consecutive readings will be relativly close, but due to the GPS's accuracy, you can get quite a large distance betwwen them. It can be fixed by increasing the time between two consecutive readings, or by ignoring some of them (i.e. take into account only each 10th reading).
Use the Haversine formula to calculate the distance between two consecutive readings. In Android it can be done with the Location.distanceTo() method.
You'll have to test it against the odometer in your car and adjust the thresholds for the accelerometer.
4 years ago, I just made an app called Landsurvayor that calculates the actual distance of two geo-graphical points drawn on Google Map. I don't know that might help you or not but there is a formula called Haversine formula that calculates the actual distance between two geo-graphical points. You might give it a try and see whether it is useful for you or not. Below is the sample code of Haversine formula:
public double CalculationByDistance(double initialLat, double initialLong,
double finalLat, double finalLong){
int R = 6371; // km
double dLat = toRadians(finalLat-initialLat);
double dLon = toRadians(finalLong-initialLong);
lat1 = toRadians(lat1);
lat2 = toRadians(lat2);
double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
return R * c;
}
public double toRadians(deg) {
return deg * (Math.PI/180)
}
More about Haversine formula:
https://en.wikipedia.org/wiki/Haversine_formula
There is another simple Android SDK built-in approach to calculate distance between two lat, lng:
Location locationA = new Location("point A");
locationA.setLatitude(latA);
locationA.setLongitude(lngA);
Location locationB = new Location("point B");
locationB.setLatitude(latB);
LocationB.setLongitude(lngB);
distance = locationA.distanceTo(locationB) ;
I hope it might help you.
You can achieve more accuracy with a combination of the following strategies.
As mentioned in other Answers, you can store the position of the mobile
every X seconds(say 10 seconds) using GPS and measure the
consecutive time between the points.
Also when the user makes quick turns, make sure to read that by
using Magnetic Sensor values too, so in such event, decrease the
"timing between position storing" to say 1-2 seconds(Will be needed for accuracy)
As a final step, use Map data(such as Google Maps etc.) to make sure
you are being tracked properly(if on road).
And then sum up all the values to get the accurate distance.
P.S. I gave information about the strategies alone since I'm not sure about its implementation in Android(or iOS).
Hope this helps :)
One problem with using GPS coordinates is that they (obviously) are not accurate. If you are travelling in a straight line, the GPS coordinates might show you travelling on a zig-zag path, hence returning a greater distance travelled than the true distance. Even with good GPS accuracy this error can be significant. Using less coordinates could result in a more accurate calculation, or not.
What you need is a way to smooth the GPS path plotted, with due consideration to your required accuracy (again a trade-off).
My first thought is to break the points into groups, and fit line segments to each group (look up "linear regression"). Then find where each consecutive line-pair overlap to define each line segment. Then simply sum the line segment lengths.
You could curve-fit segments, but that's much more intense mathematically, and might not yield a better result (and which curve formula to use?). There may be better mathematical ways I'm not aware of.
Hope this helps.
If you are looking for exact (or nearly exact) distance information, you need to track the path followed, which means checking coordinates every few seconds (depending upon expected speed traveled). You can save space by discarding the old coordinates after calculating each segment and just storing current distance traveled.
Android :: how to calculate distance while walking in android?
There are different ways to do this:
1.GPS: Keep adding GPS distance between 2 points every X seconds (say 10 sec). Check Android Location.distanceTo or distanceBetween. Check
My Tracks app, it is open source. GPS is not available indoors and
would have error if user is changing direction very frequently (read
every 1-2 second)
2.Accelerometer: Look for code/library for step detection using accelerometer. Distance comes from double integration of acceleration,
errors can add up very quickly here.
3.Step detector: Built-in in Nexus 5. Google must have taken care of accelerometer errors to extent possible. This is hardware-based
computation, consumes less battery but not available in most of
handsets as of date.
The 2nd option seem very similar to what you suggested and I do think its the best way to achieve it since iOS and Android defer in code and in functionality therefor the best method to achieve it is saving currentLocation and previousLocation in a while loop that will .sleep() and just sum the entire loop as the distance traveled.
the bigger question is this supposedly app is a distance summerizing app? does it just a small function inside of it? how do you decide when to stop calculating the distance?
If accuracy is critical, you can use data from accelerometer and gyroscope. You can find very simple formula for solving simple cinematic task so you get acc in global axis. Than you just have to use integral twice (first to get velocity, than to get position).
Just to show another perspective.
Use GPS to get lat lon of both places and after getting both pass it below method.Its will return distance in km
public static double getDistanceFromLatLonInKm(double lat1, double lon1,
double lat2, double lon2) {
double R = 6371; // Radius of the earth in km
double dLat = deg2rad(lat2 - lat1); // deg2rad below
double dLon = deg2rad(lon2 - lon1);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
+ Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2))
* Math.sin(dLon / 2) * Math.sin(dLon / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
double d = R * c; // Distance in km
return d;
}
public static double deg2rad(double deg) {
return deg * (Math.PI / 180);
}
}
Log points every x seconds (maybe 2-3?) and use distance formula below for every point logged.
Distance = sqrt((x2−x1)^2+(y2−y1)^2)
Sum them all up and you get distance

How do I predict the future position of a moving object? [duplicate]

This question already has an answer here:
How do I work out the future position of a moving object? [closed]
(1 answer)
Closed 10 years ago.
I have asked this question previously and it was closed due to it not being a programming question, this is entirely as I worded it wrong. I would like this to implemented into java. I am creating a little game and I have a photon torpedo which is being fired from a ship towards a target. Now as the speed of the torpedo is slow the ship will never hit any targets if they're moving and I want to fix this. I have drew up multiple theories and mapped out lots of mathematical stuff to find out the best way to accomplish this and in the end I deduced the following:
I find the time it takes for the photon torpedo to get to the target.
I find how far the target will have traveled in the time it takes for the torpedo to arrive.
I then find the distance between the new position of the target and the original ship.
this then gives me the opportunity to use the Cosine rule (SSS) to find out the trajectory at which the bullet needs to be fired to have a much higher chance of hitting.
Here is a digram:
Now the only problem that I need to rotate line a to the correct orientation as by default it's parallel to line c which messes up the entire equation. Can anyone help with this? And also if you can think of a better way to find the new position suggestions are very welcome. My java game entity mechanic works as follows:
Each entity has two Vectors which control movement. Position and Velocity. However, velocity is not tracked entirely properly as instead of it being a speed and a direction, to make things easier it's an xSpeed and a ySpeed.
The entities are all updates once per tick and the ship which shoots the torpedo must calculate the future position in this one tick and not over multiple ticks.
I ask this question not to be closed again, because this time I really need the answer to be implemented into Java.
This is the math i've tried so far:
double dis = level.distanceBetween(photonTargetTop, this);
double speed = 5;
double time = dis / speed;
double d1 = photonTargetTop.velocity.x * time;
double d2 = photonTargetTop.velocity.y * time;
double dis2 = level.distanceBetween(this, photonTargetTop.pos.x + d1, photonTargetTop.pos.y + d2);
double dis3 = level.distanceBetween(photonTargetTop, photonTargetTop.pos.x + d1, photonTargetTop.pos.y + d2);
double cosAngle = Math.pow(dis2, 2) + Math.pow(dis, 2) - Math.pow(dis3, 2) / 2 * dis2 * dis;
double angle = Math.acos(cosAngle);
EntityPhoton p = new EntityPhoton(this, level);
p.rotation = angle;
level.addEntity(p, pos);
Let's assume the target ship has no acceleration, meaning that it's speed and direction is not changing.
Let's also assume that once fired, your torpedo has no acceleration. And it always goes at constant speed.
Let's also call (0,0) the point where your torpedo is fired.
The ship describes a straight line. Choose a point on this line (if the ship is following a course that does not go through (0,0) you can find the closest point to the central position with some geometry that you can look up on wikipedia).
Once you have chosen the position where you want to hit the enemy ship, you know the distance between (0,0) and that position, and given that the speed of the torpedo is always the same, you can also know when to fire the torpedo.
Then you must also find the direction, meaning the values of speed to give on x and y, but that's not so difficult.
In general the problem is a system with multiple solutions, so presuming that the torpedo is faster than the target, there are infinite points where you can hit it, so you must use some heuristic to choose a point that's convenient to you.

Java/C++ - Getting 3d line from Camera yaw (heading) and pitch (no roll)

I'm aware of Quaternion methods of doing this. But ultimately these methods require us to transform all objects in question into the rotation 'space' of the Camera.
However, looking at the math, I'm certain there must be a simple way to get the XY, YZ and XZ equations for a line based on only the YAW (heading) and PITCH of a camera.
For instance, given the normals of the view frustrum such as (sqrt(2), sqrt(2), 0) you can easily construct the line (x+y=0) for the XY plane. But once the Z (in this case, Z is being used for depth, not GL's Y coordinate scrambling) changes, the calculations become more complex.
Additionally, given the order of applying rotations: yaw, pitch, roll; roll does not affect the normals of the view frustrum at all.
So my question is very simple. How do I go from a 3-coordinate view normal (that is normalized, i.e the vector length is 1) or a yaw (in radians), pitch (in radians) pair to a set of three line equations that map the direction of the 'eye' through space?
NOTE:
Quaternions I have had success with in this, but the math is too complex for every entity in a simulation to do for visual checks, along with having to check against all visible objects, even with various checks to reduce the number of viewable objects.
Use any of the popular methods out there for constructing a matrix from yaw and pitch to represent the camera rotation. The matrix elements now contain all kinds of useful information. For example (when using the usual representation) the first three elements of the third column will point along the view vector (either into or out of the camera, depending on the convention you're using). The first three elements of the second column will point 'up' relative to the camera. And so on.
However it's hard to answer your question with confidence as lots of things you say don't make sense to me. For example I've no idea what "a set of three line equations that map the direction of the 'eye' through space" means. The eye direction is simply given by a vector as I described above.
nx = (float)(-Math.cos(yawpos)*Math.cos(pitchpos));
ny = (float)(Math.sin(yawpos)*Math.cos(pitchpos));
nz = (float)(-Math.sin(pitchpos)));
That gets the normals of the camera. This assumes yaw and pitch are in radians.
If you have the position of the camera (px,py,pz) you can get the parametric equation thusly:
x = px + nx*t
y = py + ny*t
z = pz + nz*t
You can also construct the 2d projections of this line:
0 = ny(x-px) + nx(y-py)
0 = nz(y-px) + ny(z-pz)
0 = nx(z-pz) + nz(x-px)
I think this is correct. If someone notes an incorrect plus/minus let me know.

Logarithmic Mouse Movement

Alright, this is probably gonna be a pretty simple question to answer. I haven't had a math class dealing with logarithms in a few years, so I apologize. So I have a USB Controller that I'm using to control the mouse on the screen with the left joystick. Now how this works right now is the controller returns a double between 0.00 and 1.00 depending on how far the push the joystick in the direction (0.00 center, 1.00 pushed all the way over). I'm using this to adjust the speed of the mouse movement by multiplying the returned value by a given speed (returned double * speed). This gives me a linear speed. But for the purpose of accuracy of the mouse and clicking things on screen, I'd like it to be more logarithmic, so as it's really slow when barely pushing, and then the speed increases logarithmically as you move the joystick farther. That way you can get good speed for moving across the screen, while also having good sensitivity when moving it slowly. So I just need help with the formula, as I'm sure it's pretty simple. Also, I'm working in Java.
Right now my formula is:
double value (value given by controller)
int speed = 25;
value += value * speed;
I then use this to move the mouse.
Thanks,
Brayden
I presume you meant exponential. An exponential function looks like http://hotmath.com/images/gt/lessons/genericalg1/exponential_graph.gif: the more value is, the larger the derivative (the more speed will increase for the same change in value).
double value = ...;
int base = 25;
value = java.lang.Math.pow(base, value);
Not sure if java.lang.Math is necessary in its full form or whether you need to import java.lang.Math first. I'm not a Java programmer.
I agree with MvanGeest, I think you want an exponential formula. That way its small with little distance, and very big with larger distances.
I'm not sure what mouse speed values are fast or slow, but you could do something like
double value (value given by controller);
int speed (maximum speed value);
value = Math.pow(speed, value);
You could also make the value something like 2*(whatever the controller gives you) to make a wider range of speeds.
Something like:
f(value) = value * MAXSPEED * Math.Pow (base, 1 - value)
f(0) = 0 // no movement
f(1) = MAXSPEED // maximum movement when joystick is full throttle
All values should be covered in the range. Base in this case can be any value greater than 1.

Categories

Resources