Django,Bluetooth and GPS on Ubuntu Mobile
How to create a GPS enabled web application for a Mobile Internet Device
This article also appears on the community UME Guide
Background
Traditionally gps was provided on debian like systems using gpsd (apt-get install gpsd). There are however some problems using gpsd on resource constrained environments most noteably that gpsd is designed to be run at system start, and stopped when the system is shutdown (or a USB/bluetooth hotplug device started when that device is plugged in or removed). Therefore if a client is started before gpsd is running (for example a gps applet is started before the BT device is connected), then the only way for it to know about gpsd is for it to attempt to connect to the gpsd socket and keep trying every so often until it succeeds. This makes gpsd client programs very busy, always having to wake up to check to see if it can connect and on a system that runs on batteries having processes that can't sleep very often is a bad thing which drains away the battery. Also there is a problem with the granularity of the info that gpsd provides, as running clients get notified about everything, even if they don't care about it. GPS emits a new fix on every NMEA sentence received, which for most gps devices is about 5 a second and each time the clients are all woken up even if they don't care about the data that has changed.
gpsd has no way for clients to say that they are only interested in position data, or only in whether the device has a fix or not. Even if the gps unit is stationary, satellite data is constantly changing, and the clients will be woken up on every message. Because of these problems Iain Holmes at o-hand wrote gypsy. This is a gps multiplexing daemon which gives finer control of gps info and allows programs to call the following objects:
- GypsyPosition - for getting location information
- GypsyCourse - for getting course information
- GypsyAccuracy - for getting accuracy information
- GypsySatellite - for getting satellite information
Implementation
Set up a LPIA (Low Power Intel Architecture) image on Ubuntu Hardy. I chose a menlow-lpia platform.Then create a Django project called 'locate' (or something more original), however do not set up apache or postgresql. Both these applications are not suitable for an embedded device. This application will use the cherrypy standalone server (started when the system boots) and SQLite.
Edit settings.py so that it looks like:DATABASE_ENGINE = 'sqlite3' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.The
DATABASE_NAME = os.path.join(os.path.dirname(__file__), 'data', 'locate.db') # Or path to database file if using sqlite3.
DATABASE_USER = '' # Not used with sqlite3.
DATABASE_PASSWORD = '' # Not used with sqlite3.
DATABASE_NAME = os.path.join(os.path.dirname(__file__), 'data', 'locate.db')is a trick which enables the SQLite filesystem database to be stored in the project inside the folder called data. This is an advantage when using revision control systems such as subversion. A similar trick works for the site media...create a folder called media in the project root and then in settings.py put:
import os,sysThen set a STATIC_ROOT variable equal to full_path
path = os.path.dirname(sys.argv[0])
full_path = os.path.abspath(os.path.join(path, '../media'))
STATIC_ROOT = full_pathFinally, in urls.py import the django settings like
from django.conf import settingsand set the static.serve to
(r'^media/(?P.*)$', 'django.views.static.serve', {'document_root': settings.STATIC_ROOT, 'show_indexes': True}),
Also create a folder in the project root called server and inside this folder check out a copy of the standalone server:
wget http://svn.cherrypy.org/trunk/cherrypy/wsgiserver/__init__.py -O wsgiserver.pyand create a file called run.py with this in it:
import wsgiserverThe locate project should be running when the device desktop comes up so we need to start the server.Edit
#This can be from cherrypy import wsgiserver if you're not running it standalone.
import os
import django.core.handlers.wsgi
if __name__ == "__main__":
os.environ['DJANGO_SETTINGS_MODULE'] = 'locate.settings'
server = wsgiserver.CherryPyWSGIServer(
('127.0.0.1', 8000),
django.core.handlers.wsgi.WSGIHandler(),
server_name='Lowkate',
numthreads = 20,
)
try:
server.start()
except KeyboardInterrupt:
server.stop()
/usr/bin/ume-xephyr-startand add:
echo "Starting Locate"the command
export PYTHONPATH="/home/ume/Web/django_projects/locate/:$PYTHONPATH"
export PYTHONPATH="/home/ume/Web/django_projects/:$PYTHONPATH"
export DJANGO_SETTINGS_MODULE=locate.settings
python /home/ume/Web/django_projects/locate/server/run.py&
python /home/ume/Web/django_projects/locate/server/run.py&executes the python file run.py and starts the server as a background process which allows other processes (e.g. the Xephyr UI) to continue executing. The locate project should now look like:
root@ian-laptop:/home/ian/Dev/Ume/menlow-lpia/targets/target1/fs/home/ume/Web/django_projects/locate# lswhich is a completely self-contained project environment
data media server __init__.py manage.py settings.py urls.py
Test the Gypsy to GPS Connection
Install inside the target the gypsy lpia deb and library . The bluetooth GPS device I used was the Nokia Wireless GPS Module LD-3W and to communicate with it we need to find out its address. Make sure bluetooth is enabled
sudo apt-get install bluetooth bluez-utils bluez-gnome gnome-bluetooth libbluetooth2 libbtctl4 libgnomebt0 nautilus-sendtoand run:
ian@lawrence:~$ hcitool scan
Scanning ...
00:19:B7:8C:A7:F7 IansPhone
00:02:76:C5:58:B2 Nokia LD-3W
This returns the address of the GPS device - 00:02:76:C5:58:B2 There is a nice GUI for this here
Add this address into gypsy.py
59 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)and then inside a target terminal:
60
61 gps = GPS("00:02:76:C5:58:B2")
62 gps.Start()
export DISPLAY=:2The status of the GPS is displayed along with a small map of the user location pulled from a mapping API
python status.py

D-BUS and HTTP Requests
It is not possible to query DBUS without starting some sort of a loop - such as the call to
DBusGMainLoopin status.py. This will not happen in a web application and so some alternative solution is necessary. XML-RPC Requests are a way of:
"allowing software running on disparate operating systems, running in different environments to make procedure calls over the Internet. It's remote procedure calling using HTTP as the transport and XML as the encoding."
Django has an XML-RPC server already available thanks to the work of Graham Binns and Brendan Adams so install this and then make a method in settings.py like:
XMLRPC_METHODS = (and in django_xmlrc/views.py create a method signature like:
# List methods to be exposed in the form (, ,)
('locate.django_xmlrpc.views.handle_xmlrpc', 'handle_xmlrpc',),
('locate.django_xmlrpc.views.handle_gypsy', 'handle_gypsy',),
)
@xmlrpc_func(returns='string', args=['string', 'int', 'int', 'int',])The XML-RPC client needs to pass the GPS XML object to "handle_gypsy" as shown here
def handle_gypsy(timestamp, latitude, longitude, altitude):
"""Take the values we need from the the gypsy XML object and store them in a database (or file system) """
data = Raw(time=timestamp, lat=latitude, long=longitude, alt=altitude)
data.save()
# This returns the values passed in (useful for debugging)
return "The timestamp is %s, the latitude is %i, the longitude is %i, and the altitude is %i." % (timestamp, latitude, longitude, altitude)

(also create a models.py to store the data)
In gypsy.py add
2 import xmlrpcliband
63 gps.Start()which passes the GPS data into our Django web application. All that remains to do is query our database for the last GPS position. Create an application called geoapp with a views.py like
64
65 server = xmlrpclib.ServerProxy('http://127.0.0.1:8000/xmlrpc/')
66
67 def position_changed(fields, timestamp, latitude, longitude, altitude):
68 server.handle_gypsy(timestamp, latitude, longitude, altitude)
1 # Create your views here.and a template of
2
3 from django.http import HttpResponse
4 from locate.django_xmlrpc.models import Raw
5 from django.shortcuts import render_to_response
6
7
8
9 def get_position(request):
10 latest_GPS = Raw.objects.all().order_by('-id')[:1]
11
12 return render_to_response('location_list.html', {'latest_GPS': latest_GPS})
13
{% if latest_GPS %}
{% for co in latest_GPS %}
I am located at <a href="http://geohash.org/?q={{co.lat}},{{co.long}}">this</a> URL.
{% endfor %}
{% else %}
No coordinates
{% endif %}
This uses geohash.org which is a latitude/longitude geocode system invented by Gustavo Niemeyer when writing the web service at geohash.org, and put into the public domain.It offers short URLs to uniquely identify positions on the Earth, so that referencing them in emails, forums, and websites is more convenient.
Here is where I was when writing this article
.

Here is the complete application
There are many things to work on in this application. A nice maemo user applet instead of hacking the gypsy code to pass the XML would be one significant improvement as would some limit on the amount of data being passed into the database.
Also this 'blue sky' idea below seems interesting!
Further Research and Ideas
Interaction with the onboard camera.For example, user takes photo of an unknown object (like a building or landmark) and return good results about it from a search API
The Future of Internet Search Mobile Version
How To Do This:
We know the user location and now we need the software to work out what an object is ....we need to capture gstreamer output from camera and pass it to augmented reality software for visual object extraction and then overlay API search info back onto the image
tags:





More Detail?