Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I determine direction with GPS readings alone and display in 360 degrees?

I am working on an AS3 AIR for Android application. "my problem is this: given a GPS location, I want to retrieve the direction of movement (North, NW, West, SW, South, SE, East, NE)"

I would like the code for how to use 2 different GPS readings to deduce the direction of travel. I would then like to use that data for 360 degrees.

I think I understand how I can get general direction like North, South, East, and West. I would get 2 separate GPS readings and compare something like so...

See if X is greater in the 1st or 2nd GPS reading. See if Y is greater in the 1st or 2nd GPS reading. From this I should be able to see the general direction. Compare the differences of X1 and X2 with the difference of Y1 and Y2. then you can see what direction the user was headed in the most. Then display the direction.

Im not sure on how to take the data and use it for a 360 interpretation like a compass... can anyone help?

WORKING CODE-------------------------------------------------------------------------------

package 

{
import flash.display.Sprite;
// Geolocation sensor stuff
import flash.sensors.Geolocation; 
import flash.events.GeolocationEvent;
//Timer setup stuff for setting frequesncy of GPS Update
import flash.utils.Timer;
import flash.events.TimerEvent;

// Sprite and Textfield display
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;


    public class FlashTest extends Sprite 

    {
        //Variable to check if current or prior Geolocation Event fired
        private var gpsCheck:int = 1;
        public var dLon:Number


        //latitude and longitude in degrees (RAW info from Geolocation)
        public var gpsLat1:Number
        public var gpsLon1:Number
        private var gpsLat2:Number
        private var gpsLon2:Number
        public var bearing:Number


        // Latitude and longitude in radians converted from Degrees
        public var gpsLat1R:Number
        public var gpsLon1R:Number
        private var gpsLat2R:Number
        private var gpsLon2R:Number     
        private var yy:Number  
        private var xx:Number          


        public function FlashTest() 

        {
            // Text box for displaying results
            var my_txt:TextField = new TextField();
                my_txt.wordWrap=true; 
                my_txt.width = 300;
                my_txt.height = 300;
                 addChild(my_txt);

            /*
            //If GPS is on device create Geolocation object named "my_geo"
            //Request updates from my_geo every 2000 milliseconds. Run onGeoUpdate function
            //when Event is triggered. After that create the text box for displaying data.
            if (Geolocation.isSupported)
            {
                var my_geo:Geolocation = new Geolocation();
                my_geo.setRequestedUpdateInterval(2000);                
                my_geo.addEventListener(GeolocationEvent.UPDATE, onGeoUpdate);
                var my_txt:TextField = new TextField();
                my_txt.wordWrap=true; 
                my_txt.width = 300;
                my_txt.height = 300;
                addChild(my_txt);
            } 
            // If GPS is not supported on device display "No GPS Signal" 
            else
            {
                addChild(my_txt);
                my_txt.wordWrap=true; 
                my_txt.width = 300;
                my_txt.height = 300;
                addChild(my_txt);
                my_txt.text = "No GPS Signal ";
            }
            */


            // False GPS reading being passed for testing 
            //COMMENT THESE LINES OUT STARTING HERE---
                gpsLat1 =  42.1234584;
                gpsLon1 = -83.1234577;
                gpsLat2 =  42.1234583;
                gpsLon2 = -83.1234577;
           // END OF WHAT SHOULD BE COMMENTED OUT---

           // Equations to convert all RAW Geolocation information over to radians 
                gpsLat1R = gpsLat1 * Math.PI / 180;
                gpsLon1R = gpsLon1 * Math.PI / 180;
                gpsLat2R = gpsLat2 * Math.PI / 180;
                gpsLon2R = gpsLon2 * Math.PI / 180;
          // The rest of the math     
                dLon = gpsLon1 - gpsLon2;
                yy = Math.sin(dLon) * Math.cos(gpsLat2R);
                xx = Math.cos(gpsLat1R) * Math.sin(gpsLat2R) - Math.sin(gpsLat1R) * Math.cos(gpsLat2R) * Math.cos(dLon);
                bearing = Math.atan2(yy, xx) * 180 / Math.PI;
         // Run The Geoupdate function                
            onGeoUpdate();


        // onGeoUpdate basically displays the information that was collected and converted.
        // This is where you will put what you want the code to do with the results
            function onGeoUpdate():void
            {
            my_txt.text = "My Latitude is "+gpsLat1+ " and my Longitude is "+gpsLon1+ 
            "My 2nd Latitude is "+gpsLat2+" and my 2nd Longitude is "+gpsLon2+ 
            " Bearing is " +bearing;

            }            
        }
    }
}
like image 777
Catttdaddy Avatar asked Aug 29 '13 20:08

Catttdaddy


2 Answers

The formula you need (for lon1, lon2 longitudes, and lat1, lat2 latitudes of the two points) is given in many places - for example, at http://www.movable-type.co.uk/scripts/latlong.html . The math goes like this (convert it to your favorite language...):

dLon = lon2 - lon1;
y = sin(dLon) * cos(lat2);
x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) *cos(dLon);
bearing = atan2(y, x) * 180 / Pi;

Note: atan2 reduces the result to a value between [-pi, pi]. After multiplying by 180/pi the number will be between [-180,180]. In order to get a value between 0 and 360 you could do, for example:

if (bearing < 0) bearing += 360;

I hope you can fill in any other details you need to make this work for you.

EDIT I have used the numbers your gave to write a little bit of code: this is Matlab, but it should be pretty readable:

% bearings
lat1 = 42.1234584;
lat2 = 42.1234583;
lon1 = -83.1234577;
lon2 = -83.1234510;

% convert to radians:
g2r = pi/180;
lat1r = lat1 * g2r;
lat2r = lat2 * g2r;
lon1r = lon1 * g2r;
lon2r = lon2 * g2r;
dlonr = lon2r - lon1r;
y = sin(dlonr) * cos(lat2r);
x = cos(lat1r)*sin(lat2r) - sin(lat1r) * cos(lat2r)*cos(dlonr);

% compute bearning and convert back to degrees:
bearing = atan2(y, x) / g2r;

fprintf(1,'x: %+.3e\ny: %+.3e\nbearing: %.3f\n', x, y, bearing);

This results in the output:

x: -1.745e-09
y: +8.673e-08
bearing: 91.153

As you can see, x and y are tiny - they represent the "fraction of the circumference of the earth" that you moved (about 3.5 meters due East, it would seem...). You should be able to debug your implementation with these numbers.

Notice by the way that GPS can have a poor "absolute" accuracy (in your case, uncertainty of > 100 m), yet still be good with "relative" accuracy (it measures the difference between two positions much better than 100 m).

like image 148
Floris Avatar answered Sep 21 '22 11:09

Floris


if you are using the Location API then when your location changes you get a callback giving you a Location object which you can get the bearing of the direction moved from 0-360 degrees

like image 22
tyczj Avatar answered Sep 19 '22 11:09

tyczj