Determine building your Android device is pointing at - android

I have a MapView in which I am drawing buildings on using geopoints. Currently, the app determines the closest building to you by just checking your long/lat and comparing to the buildings; but what I want to be able to do is point my device at a building and have that buildings info pop up, even if it isn't the closest building to you.
I have looked up how to accomplish this and I would be using the azimuth direction received from the ORIENTATION sensor listener. I am having trouble using that azimuth direction and determining if it is intercepting one of the buildings on the map.
Would I be using the ORIENTATION sensor and azimuth to accomplish this? How would I go about implementing this? Any help appreciated!

Figured out the solution:
I used this function(and helper function) to get the bearing from my current location to the closest buildings around me(using a set radius):
public static float calculateBearing(GeoPoint before, GeoPoint after) {
Point pBefore = location2Point(before);
Point pAfter = location2Point(after);
float res = -(float) (Math.atan2(pAfter.y - pBefore.y, pAfter.x
- pBefore.x) * 180 / Math.PI) + 90.0f;
if (res < 0)
return res + 360.0f;
else
return res;
}
public static Point location2Point(GeoPoint aLocation) {
return new Point((int) (aLocation.getLongitudeE6()),
(int) (aLocation.getLatitudeE6()));
}
Once you have the bearings of the buildings around you; you must then compare that to the bearing your phone is positioned at using a SensorEventListener for the TYPE_ORIENTATION sensor to find out which of the closest buildings your pointing at.

Related

How to detect device is moving or not using sensor android

I am using below code to identify the movement of the device, means I would like to know that device is moving or not. I also use Google Activity APIs which provides different activity modes like WALKING, ON_FOOT, STILL, etc without using GPS. I would like to achieve the same with Sensors but I am not able to get it accurately.
The issue with the following code is that as soon as I move the device quickly like take it from the table then I am getting the result as moving whereas it's not actually moving.
// calling method from onSensorChanged method and using TYPE_ACCELEROMETER sensor.
double speed = getAccelerometer(event.values);
// then checking the speed.
if(speed > 0.9 && speed < 1.1) {
// device is not moving
} else {
// device is moving.
}
/**
* #return
*/
private double getAccelerometer(float[] values) {
// Movement
float x = values[0];
float y = values[1];
float z = values[2];
float accelerationSquareRoot =
(float) ((x * x + y * y + z * z) / (9.80665 * 9.80665));
return Math.sqrt(accelerationSquareRoot);
}
Can anyone guide me how to make this logic accurate so that I can identify the device is moving or not?
The accelerometer is made to return acceleration data and according to Netwon's 2nd law if the acceleration is constant then the body is not moving or moving with constant speed(this is quite impossibile in your case).
Therefore if you keep reading the same data on all three axis(or better in a quite strict range) from accelerometer over time it means the phone is not moving otherwise it is.
For the purpose, you need to use Activity Recognition API which will provide you some events like moving, stop, driving, e.t.c, And activity recognize use some sensor data and also help of location service when is running. For the more how we can use and what actually it. You can read from below link
https://developers.google.com/location-context/activity-recognition/

Detect if device has taken a turn using location service android

I want to detect if the user has taken a turn on the road while driving using the sensors on the android phone. How do I code this? I am collecting data live from all the sensors(accelerometer,location,rotation,geomagnetic) and storing them on the sd card. So now i just want to know whether the user has a taken a turn and in which direction he has turned.
I assume the registration of the sensor is done properly. You can detect the direction by using the orientation sensor (deprecated) as follows:
#Override
public void onSensorChanged(SensorEvent event) {
float azimuth_angle = event.values[0];
int precision = 2;
if (prevAzimuth - azimuth_angle < precision * -1)
Log.v("->", "RIGHT");
else if (prevAzimuth - azimuth_angle > precision)
Log.v("<-", "LEFT");
prevAzimuth = azimuth_angle;
}
Note: The variable of "prevAzimuth" is declared as global. You can change "precision" value to whatever you want. We need this value because we do not want to see output after each trivial change in azimuth angle. However, too large precision gives imprecise results. To me, "2" is optimum.
If you are tracking location coordinates, you can also track shifts between the angle from previous locations.
angle = arctan((Y2 - Y1) / (X2 - X1)) * 180 / PI
See this answer for calculating x and y.
Decision to use sensor values is based on an unrealistic assumption that the device is never rotated with respect to the vehicle.

Android, using gps and compass to point towards coordinate

I'm trying to make an app that points you toward a position. You press a button and it stores the gps coordinates, then calculates things like distance and the angle you need to face. Then it leads you back to that remembered position by "pointing" toward it using an onscreen compass graphic.
At least, it's supposed to. After messing with the code for hours, I've come to the conclusion that there's just a logic error somewhere due to my lack of trig practice over the past few years.
The compass and GPS position are updated fairly frequently. This is the code in my main update call for the user interface that rotates the compass and displays the distance.
public void updateUI(){
double deltaX = targetLongitude - currentLongitude;
double deltaY = targetLatitude - currentLatitude;
double distance = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
double rotation = Math.toDegrees(Math.atan2(deltaX,deltaY));
distanceTextView.setText(Double.toString(distance));
rotateCompass(rotation - degreesClockwiseFromNorth);
}
and the code for rotateCompass:
public void rotateCompass(double degrees){
degrees -= currentRotation; //calculates necessary rotation across updates
currentRotation += degrees;
matrix.postRotate(
(float) degrees,
compass.getDrawable().getBounds().width() / 2,
compass.getDrawable().getBounds().height() / 2);
compass.setImageMatrix(matrix);
}
I'm almost certain my rotation code works because when I replace
rotateCompass(rotation - degreesClockwiseFromNorth);
with
rotateCompass(0 - degreesClockwiseFromNorth);
it points north right alongside a real compass regardless of the direction I'm facing. But when I use the former, it points towards a consistent point, but that point seems to be nowhere near the target point.
So I've come to the conclusion my error is either in calculating the correct angle, or expecting the gps to be too precise. I haven't tested it for distances further than what I can in my backyard, but I assume that if it was a gps accuracy issue I'd see my compass jumping all over the place rather than adamantly pointing in a wrong direction.
Thanks for reading, any suggestions or corrections are appreciated.
Your math is all screwed up because the distance between 2 degrees of longitude is not the same as 2 degrees of latitude. In fact, it isn't even a constant length for longitude- its shorted by the poles and longest at the equator. Use the Location.distanceTo functions instead.

Approximate indoor positioning using the integration of the linear acceleration

I am trying to calculate the approximate position of an Android phone in a room. I tried with different methods such as location (wich is terrible in indoors) and gyroscope+compass. I only need to know the approximate position after walking during 5-10seconds so I think the integration of linear acceleration could be enough. I know the error is terrible because of the propagation of the error but maybe it will work in my setup. I only need the approximate position to point a camera to the Android phone.
I coded the double integration but I am doing sth wrong. IF the phone is static on a table the position (x,y,z) always keep increasing. What is the problem?
static final float NS2S = 1.0f / 1000000000.0f;
float[] last_values = null;
float[] velocity = null;
float[] position = null;
float[] acceleration = null;
long last_timestamp = 0;
SensorManager mSensorManager;
Sensor mAccelerometer;
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() != Sensor.TYPE_LINEAR_ACCELERATION)
return;
if(last_values != null){
float dt = (event.timestamp - last_timestamp) * NS2S;
acceleration[0]=(float) event.values[0] - (float) 0.0188;
acceleration[1]=(float) event.values[1] - (float) 0.00217;
acceleration[2]=(float) event.values[2] + (float) 0.01857;
for(int index = 0; index < 3;++index){
velocity[index] += (acceleration[index] + last_values[index])/2 * dt;
position[index] += velocity[index] * dt;
}
}
else{
last_values = new float[3];
acceleration = new float[3];
velocity = new float[3];
position = new float[3];
velocity[0] = velocity[1] = velocity[2] = 0f;
position[0] = position[1] = position[2] = 0f;
}
System.arraycopy(acceleration, 0, last_values, 0, 3);
last_timestamp = event.timestamp;
}
These are the positions I get when the phone is on the table (no motion). The (x,y,z) values are increasing but the phone is still.
And these are the positions after calculate the moving average for each axis and substract from each measurement. The phone is also still.
How to improve the code or another method to get the approximate position inside a room?
There are unavoidable measurement errors in the accelerometer. These are caused by tiny vibrations in the table, imperfections in the manufacturing, etc. etc. Accumulating these errors over time results in a Random Walk. This is why positioning systems can only use accelerometers as a positioning aid through some filter. They still require some form of dead reckoning such as GPS (which doesn't work well in doors).
There is a great deal of current research for indoor positioning systems. Some areas of research into systems that can take advantage of existing infrastructure are WiFi and LED lighting positioning. There is no obvious solution yet, but I'm sure we'll need a dedicated solution for accurate, reliable indoor positioning.
You said the position always keeps increasing. Do you mean the x, y, and z components only ever become positive, even after resetting several times? Or do you mean the position keeps drifting from zero?
If you output the raw acceleration measurements when the phone is still you should see the measurement errors. Put a bunch of these measurements in an Excel spreadsheet. Calculate the mean and the standard deviation. The mean should be zero for all axes. If not there is a bias that you can remove in your code with a simple averaging filter (calculate a running average and subtract that from each result). The standard deviation will show you how far you can expect to drift in each axis after N time steps as standard_deviation * sqrt(N). This should help you mathematically determine the expected accuracy as a function of time (or N time steps).
Brian is right, there are already deployed indoor positioning systems that work with infrastructure that you can easily find in (almost) any room.
One of the solutions that has proven to be most reliable is WiFi fingerprinting. I recommend you take a look at indoo.rs - www.indoo.rs - they are pioneers in the industry and have a pretty developed system already.
This may not be the most elegant or reliable solution, but in my case it serves the purpose.
Note In my case, I am grabbing a location before the user can even enter the activity that needs indoor positioning.. and I am only concerned with a rough estimate of how much they have moved around.
I have a sensor manager that is creating a rotation matrix based on the device orientation. (using Sensor.TYPE_ROTATION_VECTOR) That obviously doesn't give me movement forward, backward, or side to side, but instead only the device orientation. With that device orientation i have a good idea of the user's bearing in degrees (which way they are facing) and using the Sensor_Step_Detector available in KitKat 4.4, I make the assumption that a step is 1 meter in the direction the user is facing..
Again, I know this is not full proof or very accurate, but depending on your purpose this too might be a simple solution..
everytime a step is detected i basically call this function:
public void computeNewLocationByStep() {
Location newLocal = new Location("");
double vAngle = getBearingInDegrees(); // returns my users bearing
double vDistance = 1 / g.kEarthRadiusInMeters; //kEarthRadiusInMeters = 6353000;
vAngle = Math.toRadians(vAngle);
double vLat1 = Math.toRadians(_location.getLatitude());
double vLng1 = Math.toRadians(_location.getLongitude());
double vNewLat = Math.asin(Math.sin(vLat1) * Math.cos(vDistance) +
Math.cos(vLat1) * Math.sin(vDistance) * Math.cos(vAngle));
double vNewLng = vLng1 + Math.atan2(Math.sin(vAngle) * Math.sin(vDistance) * Math.cos(vLat1),
Math.cos(vDistance) - Math.sin(vLat1) * Math.sin(vNewLat));
newLocal.setLatitude(Math.toDegrees(vNewLat));
newLocal.setLongitude(Math.toDegrees(vNewLng));
stepCount =0;
_location = newLocal;
}

How to rotate map view smoothly with bearing in android

I am trying to rotate map view when the user changes his direction ie if user takes left and right turns it should rotate accordingly.I am rotating map view basing on current location bearing it is rotating correctly but it was jittering.Here is the code which i used for rotation
public void onGPSUpdate(Location location)
{
boolean check=isBetterLocation(location, tempLoc);
tempLoc=location;
if(check){
showLocation(location);
}
}
isBetterLocation method is copied from google docs for better location.
private void showLocation(Location loc){
mRotateView.rotate(-loc.getBearing());
}
I registered a location updates with time interval 0 and min distance of 10 for frequent updates.Here my problem is map view is jittering always,can any one tell me how can I smoothly rotate map view like other applications like waze maps do.Thanks...
are you trying to rotate the map in a smooth way such as by one degree at a time or just have it go from degree A to degree B on location update ?
Something like
while (oldAngle != newAngle)
{
mapView.rotate(newAngle);
// this is where you would decied to add or subtract;
newAngle ++ or -- ;
}
not sure if this would work exactly as the loop would run really quickly so maybe do this as a asynctask and add a pause in there to simulate a smooth rotation.
Double angle = Math.atan2((userstartPoint.getX() - userendPoint.getX()), userstartPoint.getY() - userendPoint.getY());
angle = Math.toDegrees(angle);
map.setRotationAngle(angle);
so basically I get the start point (new location) and then the end point (old location) and do a Math.atan2 on it as you can see. Then convert that to a degree and set it to my map rotation.
Now it does not do a smooth rotation but I don't need that. Here is where you could set up your own stepper for a smooth rotate. Unless the google maps already has one.
As the bearing values of the Location are not very exact and tend to jump a little, you should use a filter for the bearing. For example, keep the last 5 bearing-values in an array and use the average of those values as the bearing to rotate the map to. Or use the filter explained in the SensorEvent docs - it's easier to use and can be tweaked better.
This will smoothen out the rotation of the map resp. keep it more stable.
EDIT:
A version of the low-pass filter:
public static float exponentialSmoothing(float input, float output, float alpha) {
output = output + alpha * (input - output);
return output;
}
use it like so:
final static float ALPHA = 0.33; // values between 0 and 1
float bearing;
// on location/bearing changed:
bearing = exponentialSmoothing(bearing, newBearing, ALPHA);
bearing would be the value to use to actually rotate the map, newBearing would be the bearing you get from every event, and with ALPHA you can control how quickly or slowly the rotation acts to a new orientation by weighting how much of the old and the new bearing is taken into account for the result. A small value weighs the old value higher, a high value weighs the new value higher.
I hope that works out better.
To change the bearing of your map, use the Camera class. You can define a new CameraPosition with the new bearing and tell the camera to move with either GoogleMap.moveCamera or GoogleMap.animateCamera if you want a smooth movement.
I have implemented this in my app. What I basically did is that I took the last and second last LatLng of my path and calculate bearing by using
public static float getRotationAngle(LatLng secondLastLatLng, LatLng lastLatLng)
{
double x1 = secondLastLatLng.latitude;
double y1 = secondLastLatLng.longitude;
double x2 = lastLatLng.latitude;
double y2 = lastLatLng.longitude;
float xDiff = (float) (x2 - x1);
float yDiff = (float) (y2 - y1);
return (float) (Math.atan2(yDiff, xDiff) * 180.0 / Math.PI);
}
Set this angle as bearing to camera position.
Note: Sometimes (rarely) it rotates map to opposite direction. i am looking for it but if anyone got reason do reply.

Categories

Resources