Position dependent event triggering on the Nokia N900

alternate text

Retrieve destination's coordinates

The program is first served with a destination address, the user input is realized as follows:

addr = raw_input('\nAddress: ') # Read destination address.

A sample input could be "Karl-Wilhelm-Strasse 4, Karlsruhe". The destination's coordinates can be retrieved by starting a Google Maps request.

# Encode query string into URL
url = 'http://maps.google.com/?q=' + urllib.quote(addr) + '&output=js'
# Get location as XML file
xml = urllib.urlopen(url).read()

Google Maps responds with a XML-file, the following code extracts longitude and latitude to the variables latDest and longDest:

# Strip lat/long coordinates from XML
latDest, longDest = 0.0,0.0
center = xml[xml.find('{center')+9:xml.find('}',xml.find('{center'))]
center = center.replace('lat:', '').replace('lng:', '')
latDest, longDest = center.split(',')
latDest, longDest = float(latDest), float(longDest)

Given the example user input from above, variables latDest and longDest will contain the following coordinates:

  • latDest: 49.010149 # Destination latitude
  • longDest: 8.420162 # Destination longitude

The Python API googlemaps leads to the same result:

from googlemaps import GoogleMaps
gmaps = GoogleMaps(API_KEY) # Set API_KEY to your Google Maps API Key
address = 'Karl-Wilhelm-Strasse 4, Karlsruhe'
lat, lng = gmaps.address_to_latlng(address)

The API can only be used with a valid Google accout and a valid API key.

Get actual position

The actual position can be retrieved from the Nokia N900 GPS receiver GPS5030 (Texas Instruments). The receiver supports Assisted GPS (A-GPS) and can be controlled by liblocation. The library is availlable as C and Python implementation and provides two objects control and device that have to be initialized as follows:

control = location.GPSDControl.get_default()
device = location.GPSDevice()

GPSDControl can be used to start and stop the receiver. The position update interval can be set by method set_properties() and has to fit the form of movement. The following code snippet sets the interval to 60 s (suitable for pedestrians):

control.set_properties(preferred_interval=location.INTERVAL_DEFAULT)

GPSDevice provides information about the receiver status and the actual GPS data (the fix) as tuple (immutable list). This fix-tuple contains the following information:

  • time stamp
  • latitude and longitude of the actual position
  • height
  • velocity

After initialization of GPSDControl and GPSDevice, latitude and longitute can be accessed as follows:

latPosition = float(device.fix[4])  # Latitude of actual position
longPosition = float(device.fix[5]) # Longitude of actual position.

Great-circle distance (orthodromic distance)

alternate text

The great-circle distance or orthodromic distance is the shortest distance between two points on the surface of a sphere, measured along the surface of the sphere. In other words: the great-circle distance is the the shortest connection between two GPS coordinates.

By calculating the orthodromic distance, one can calculate the distance between the actual position (A) and the final destination (B). Longitude and latitude have to be converted into radian measure. The central angle between them, is given by the spherical law of cosines. The distance in meters can be calculated by mutliplying the central angle by the earth radius (approx. 6370 km).

def SphericalDistance(latPosition,longPosition):
  longDestRad = (longDest * (2 * pi / 360))
  latDestRad = (latDest * (2 * pi / 360))
  longPositionRad = (longPosition * (2 * pi / 360))
  latPositionRad = (latPosition * (2 * pi / 360))

  distance = sin(latDestRad) * sin(latPositionRad) + cos(latDestRad) * \
             cos(latPositionRad) * cos(abs(longPositionRad - longDestRad))
  if ((distance >= 1) or (distance <= -1)):
      distance = 0
  else:
      distance = acos(distance)
      distance = distance * 6370000 # Change this for other planets.
  return distance # orthodromic distance

Position dependent event triggering

Variable distance returned by method SphericalDistance() contains the air-line distance between the actual position and the final destination in meters. Comparing distance with a given minimal distance makes it possible to trigger one of the following events when distance is lower or equal to the minimal distance:

  • Play an audio file ("You will arrive in about 5 minutes").
  • Toggle one or more LEDs (at night).
  • Send SMS ("I will arrive in about 5 minutes").

The following code listing shows how the Nokia N900 can be forced to send a SMS.

def SendSMS():
  string = 'at+cmgs='+"\""+number+"\""+'\r'
  child = pexpect.spawn('pnatd');
  child.send('at\r');
  time.sleep(0.25);
  child.send('at+cmgf=1\r');
  time.sleep(0.25);
  child.send(string);
  child.send('Schatz mach das Essen warm!');
  child.send(chr(26));
  child.send(chr(26));
  child.sendeof();