I working on an app that I need to calculate distance travelled from point A to point B (by car).
I asked Elm Electronics (chipset manufacturer) and they said there is no standard OBD-II PID to return mileage from odometer, although car manufacturers might provide a PID. Since this way is not standard then I found another way.
PID 0131 (Distance traveled since codes cleared), is returning something that I think might be helpful. IF i'm able to clear it at point A and read its value at point B then I'm done :)
I thought a lot to guess what does "codes cleared" mean but I couldn't realize what does it mean? and my another important question, how to clear code or reset this PID?
Any suggestion would be appreciated. Thanks.
Update
I just tested on two Cars.
On Benz car no OBD-II command works. I couldn't get any data :(
I got correct reply on Persona car (Local Malaysia) but 0x0131 PID was always returned 7F01 which is 16608KM even after passing few Kms. I tried to reset it by sending 04 command (as Eric suggested on his answer), However, nothing got clear :) and I still got 7F01 as response.
My Library can be used for anyone who is looking for OBD-II lib from here.
So, What I plan to do is, since I'm able to get speed (v) then I'm able to calculate distance based on d = v * t formula.
Elm Electronics are right. The resetting trouble codes solution is a possible, but maybe unwanted workaround though.
Mode 04 is for resetting the codes. Sending 04 will reset the MIL (Malfunction Indicator Light) and reset the codes you want to reset.
In the comments, Chris suggested to use the value, and than keep track of this value yourself. That way you don't need to misuse the Mode 04.
Th 0131 value overflows at 65535 km. But when you bring you car in for maintenance, they could reset this value, depending on who is maintaining your car ofcourse.
Source: Mode 04 - Wikipedia
There are two PIds: 0x0121 Distance travelled with malfunction indicator lamp (MIL) on which keeps the distance with MIL on and 0x0131 Distance travelled since codes cleared which keeps the distance after clearing the MIL by using mode 0x04. By saying code, it meant the Diagnostics Trouble Code (DTC). When one of them keeps counting the distance the other one is fixed and activation is done for them only based on MIL on or off.
For having the milage, afaik, you need to have current mileage from the odometer as the reference, in addition to those two PIDs. For example, if the current mileage on the odometer* is X and the first time readings for those two PIDs are Y and Z respectively, and x and y are real-time readings from those two PIDs, these two formulas can give you the mileage and trip distance:
Real-Time mileage** = X + (y - Y) + (z - Z)
Trip distance (MIL Off) = x(end) - x(start)
Trip distance (MIL On) = y(end) - y(start)
*The odometer is supposed to be available by PID 0x01A6 Odometer, but in almost all the vehicles, it's not supported.
**The overflow in readings from those two PIDs should be considered as well.
I think You can use the PID 0x011F (Run time since engine start) and PID 0x010D (Vehicle speed). If you save these values in an sd card then you can multiply these two values.
Related
I am using the FusedLocationProviderClient to get locationUpdates after setting up LocationRequest properties.
To calculate 'distance traveled' I thought I would do the following:
Location lastLocation; // initialized to start location with getLocation() - code not shown.
LocationCallback locationCallback;
Double DistanceTraveled = 0.0;
locationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult != null) {
// Get last location in result if more than one are returned.
Location thisLocation = locationResult.getLastLocation();
// Sum up DistanceTraveled
DistanceTraveled = DistanceTraveled + lastLocation.distanceTo(thisLocation);
// Save thisLocation for next time onLocationResult() is called
lastLocation.set(thisLocation);
}
}
}
Well, this doesn't work very well. On every callback, the exact location changes by 0 meters to 10 meters randomly just due to the accuracy of the result. So, if I am standing perfectly still for 10 minutes with a 5 second update using this algorithm, it will sum up several meters that I have traveled, when I haven't moved at all!
What should I be doing to get an accurate accounting of my distance traveled? What options exist?
Ok - it has been 12 days since I posted my question here. Lots of reading, testing, coding, more testing, more reading. I now have a responsibility to contribute to the site that gives so much to me. So here goes.
First, the following post has many tidbits of info and links to assist. calculate actual distance travelled by mobile
Now, I am specifically concerned about tracking the distance traveled by someone walking; to be exact while bird watching. My app is for bird watchers. So, I am interested in logging the birds seen, along with where, and tracking the overall distance walked. It turns out these are two different issues. Getting the current coords for a sighting of a bird is easy stuff; just get the location. The accuracy is that which is reported.
Now, to the problem of this post. Calculating distance walked. That is a different problem altogether. And this is what I was looking for when posting the question. How do people get an accurate accounting of distance traveled, when walking? Because just registering for location updates and then summing up the Location1.distanceTo(Location2) usually gives one a wildly inflated total distance. Why? I didn't understand the problem. Now I do. And if I had this understanding, then the path to the solution would have been clearer.
Let me give an example. Let's say I walk for 10 seconds. At second 0 (t0) is where I start. And let's say I move 1 meter by t1. I stand at this position until t5, and then walk for another 5 seconds until t10. A combination of walking/standing help to illustrate the problem.
Each GPS location update contains a coordinate (lat/lng), or a point, along with an accuracy rating in meters. Along with other data, but the only other one I care about is time in milliseconds. In this example, always 1000 ms more than the last update.
Think of this GPS update as a point at the epicenter of a circle with radius accuracy-in-meters as returned. Your actual location could be anywhere within that circle or on the circle's edge, in theory. Not sure how accurate that accuracy-in-meters is (seems like it should have it's own accuracy rating), but let's assume it is accurate, and your true location is no more than accuracy-in-meters away from the point reported. In fact, let's assume it is always that distance from your true location for purposes of illustration. Let's also assume that this accuracy-in-meters is 20m in this example for each point returned.
So, at t0, my true location could be 20m ahead of where it reported. I walk 1 meter forward and location update at t1 reports I am 20m ahead of where I truly am. So, computing t0.distanceTo(t1) reports that I have moved 40m when I have truly only moved 1m. Starting to see the picture? Read on...
Now, I stand here until t5. And I get 4 more location updates, which for example purposes, are 20m ahead, 20 meters behind, 20 meters to my left and 20 meters to my right. (This is an extreme example, but uses easy numbers for illustration). So, in addition to my supposed 40m of travel after 1 second, it now thinks I have moved approximately 20x4 or 80m more, for a total of 120m. And I have only moved 1m in reality! Continue to walk 5 more meters to t10 and your distance could again be 5x20 or 100m more for a total of 220m, when you have only walked 6m in 10 seconds. That is why simply summing up distance traveled will never be accurate as long as there is any error in the accuracy.
That's the problem. And until one understands that, you are befuddled by how this crappy Galaxy S9 is doing this to you.
What about averaging points? "midpoint(t0,t1).distanceTo(midpoint(t2,t3)" and so on? This will always produce less-than true distance traveled. Depending on movement, sometimes by a lot.
There are lots of methods (see link above) to try in order to reduce the error in Distance Traveled calculations. I have found that my method below produces more accurate results when walking, than Google's MyTracks app. I have repeatedly tested at 200m, 500m and 1000m distances. And this consistently produces good results usually with < 10% error. Half the time, Google's MyTracks says I have walked 500m+ on the 200m test.
onLocationResult(LocationResult locationResult) {
lastLocationReceived.set(locationResult.getLastLocation());
// Throw away updates that don't meet a certain accuracy. e.g. 30m
if (lastLocationReceived.hasAccuracy() && locatLocationReceived.getAccuracy() <= MIN_ACC_METERS_FOR_DISTANCE_TRAVELED) {
// Don't use it if the current accuracy X 1.5 > distance traveled since last valid location
if ((lastLocationReceived.getAccuracy() * 1.5) < loastLocationReceived.distanceTo(lastLocationUsedForDistanceTraveled) {
// Calculate speed of travel to last valid location; avg walking speed is 1.4m/s; I used 2.0m/s as a high end value.
// Throw away values that are too high because it would have required that you run to get there.
// Sometimes the location is somewhere you could not have gotten to given the time.
long timeDelta = lastLocationReceived.getTime() - lastLocationUsedForDistanceTraveled.getTime();
if ((lastLocationReceived.distanceTo(lastLocationUsedForDistanceTraveled) / timeDelta) > MAX_WALKING_SPEED) {
// NOW we have a value we can use to minimize error
distanceTraveled += lastLocationReceived.distanceTo(lastLocationUsedForDistanceTraveled);
// Update last valid location
lastLocationUsedForDistanceTraveled.set(lastLocationReceived);
}
}
}
};
Notes:
onPause() for activity stop locationUpdates.
onResume() restart locationUpdates.
Setting/using locationRequest.setSmallestDisplacement() produced strange results for me. I ended up never setting this value in my locationRequest. How does it know you have moved 5m when the hAccuracy is 20m?
I don't find a need to keep getting location updates with the app paused (in one's pocket). As soon as you pull you phone out of your pocket to use it to record a sighting, it reacquires fairly quickly. More testing may prove that this is error prone. But for now, it seems to be ok.
I have tested more methodologies than I can remember with wildly differing results. This simple method works best, for WALKING, in my tests. I am sure there is more that I could do that might further refine the error by a few percentage points. If anyone has concrete examples for how to achieve tighter accuracy, please post comments.
In my testing, I created an activity that allowed me to adjust locationRequest() settings in real time (stop and restart locationUpdates required on changes); as well as modifying min accuracy levels and accuracy multiplier (used above in code as 1.5). So I was able to test and play with different parameter settings to see what produced the best results.
I hope this helps others get started down this path for the first time. Would love to hear comments, corrections, improvements if anyone has some.
I am trying to read the distance traveled since some codes were cleared from the OBD with an Android application.
I have managed to get the RPM and fuel % to work but the distance traveled is higher than what I would expect.
case 49: //PID(31): Distance Travelled(A*256)+B
Double miles = (((valueA*256)+valueB)*0.62137;
String displayDistance = String.valueOf("Miles: " + miles);
Anyone know where I've gone wrong?
I have discovered the code is right but not 100% accurate because I parsing the bytes into an int and therefore calculation is out by about 7 miles. Will need to find a way to parse as a double. The issue when I am thousands of miles out is a concurrent issue with interleaving of a shared variable.
In my application i want to know the transmit power of a mobile phone when i received from it data (beacon, file, ..). I need to know the transmit power, to use it in distance calculations using Received Signal Strength Indicator (RSSI).
How i can do that?
Ok, to measure distance using signal dampening:
There are different way of doing this. The most basic way is using open space dampening, where you get reference values inside a certain space, e.g a room. Any new furniture or change in surface material affect these values. This document is some guys thesis or something about the subject, you might want to check this out: http://www.s2is.org/Issues/v1/n2/papers/paper14.pdf. Good location is difficult especially, because the dampening is not linear.
This function is for theoretican dampening in open space:
L = 20 log(d) + 20 log(f) + 36.6,
where L is dampening in Db
f is frequency in MHz
and d is distance in miles.
This is the radio theory
So, this is a common problem in apps that track your location over a journey (a run or cycle workout, for example).
Clearly GPS navigators have less trouble, since they can assume you snap to a point on a road - however, if you're running in the park, snapping to some road grid is going to give you totally crazy numbers.
The problem as far as I see it is to combine the great-circle distances between the waypoints, but taking into account the errors (accuracy values) such that you don't veer off course too far for a low-accuracy point. The rough implementation in my head involves plotting some bezier curve (using the velocity/bearing at the point to add spline direction and weight) and integrating over it.
However, clearly this is something people have sovled before. Anyone know of the implementations, or are they all buried in proprietary software?
Bonus points for anyone who can also use the (mostly) less accurate cell tower points (which come with different/out-of-sync timestamps, and no velocity or bearing information).
The eventual implementation will be in javascript or python, whichever is faster (I'm using SL4A,) but I'm looking for general algorithms here.
To get everyone started, here is the naive algorithm, not using any velocity or bearing info.
The arc length s is calculable from the two (long, lat) pairs (the start and end waypoints) of the segment we'll start with, by the standard formula.
Assuming we've converted the value pairs into standard spherical coordinates phi and theta (here as arrays, so using phi[0] and phi[1] for locations 0 and 1) in radians, the arc length is just:
from math import sin, cos, arccos, sqrt
s = arccos(
sin(phi[0]) * sin(phi[1]) * cos(theta[0] - theta[1]) +
cos(phi[0]) * cos(phi[1])
)
However, since we've got a massive horrid function, we need to use the chain rule to work out the first order errors, and we get the following monster for delta_s:
delta_s = (1.0 / abs(sin(s))) * (
delta_phi[0] * abs(
sin(phi[0]) * cos(phi[1]) -
cos(phi[0]) * sin(phi[1]) * cos(theta[0] - theta[1])
) +
delta_phi[1] * abs(
sin(phi[1]) * cos(phi[0]) -
cos(phi[1]) * sin(phi[0]) * cos(theta[0] - theta[1])
) +
(delta_theta[0] + delta_theta[1]) * abs(
sin(phi[0]) * sin(phi[1]) * sin(theta[0] - theta[1])
)
)
We perform this operation on every pair of successive points in order, sum the ss, add the errors in quadrature as normal:
accumulator = 0.0
for error in errors:
accumulator += error * error
journey_error = sqrt(accumulator)
and thus, we know the uncertainty on our rubbish distance estimate. (we can even keep the accumulator around to speed up the calculation if we add a few points on the end - as we could in practise with real time data.)
However, this is going to give us huge errors, and only a very fuzzy idea of how far we've actually gone. This can't be how actual GPS equipment estimates distances, as it would never be accurate enough unless it had amazing signal all the time:
What we need is some more nuanced path approximation, which only bends the path out of position for the type of inaccurate points shown, rather than diverting it completely and massively increasing the distance estimate — in asking the question I was hoping to find out how all the existing implementations (probably) do it!
I have in my android application a database table with geo pointes (lat and lon are decimal degree values), about 1000 points. And I need to select 20 nearest point to some given geo point.
I've found at Stackoverflow the answer how to compute distance between two geo points and was very happy, till I tried to write my query. I've found out, that it's not possible to use trignometrical functions in built-in sqlite of android.
But then I've got an Idea. I don't really need to compute a distance. The near a point is to another one the smaller difference in their geo coordinates should be.
How could I use this fact? Would it be enough to order saved points by (lat_0 - lat_n)^2 + (lon0-lon_n)^2, where lat_0 and lon_0 are geo coordinates of a given point?
Thank you,
Mur
UPD
So, the best way to get an answer for my question was to test approach I describe above.
It works pretty well but not really exactly compared to exact distance.
So if you just need to compute a distance, this solution is ok, but in my case I also needed to order stations by distance and couldn't use this solution.
My thanks go on John at CashCommons and Philip. Thank you guys
If your points are separated within a city (more or less), that approximation will work fine. The approximation falls apart if you go worldwide, though.
EDIT: Based on Philip's comment below, you should scale one of the components. Germany is about 50 degrees north latitude, so multiplying the longitude by (cos 50 deg) will do better.
Yes. :-) The actual distance is sqrt( (lat_0 - lat_n)^2 + (lon0-lon_n)^2 ) but ordering by (lat_0 - lat_n)^2 + (lon0-lon_n)^2 is sufficient.
Hmm... I'm not sure how that ordering would work? Wouldn't you need a different order for each point to indicate it's neighbors.
The simplest solution is to just iterate through all the points and compute the geometrical distance between the points. For 1000 points this should happen fairly fast.
The most optimized solution (in terms of retrieval speed) is to compute the neighbors of each point when you insert them in the database. For example you can keep the list of ids as a comma separate string and insert in the database?. Then when you need someones neighbors you do directly to them. However this is going to become a pain if you need to insert new points. Basically you'll need to re-compute the neighbors.