Обновление положения карты Google на основе координат GPS - PullRequest
1 голос
/ 29 декабря 2011

У меня Arduino с GPS-чипом, обрабатывающим строки NMEA с Python. У меня есть файл HTML, который я открываю, и я автоматически обновляю его каждые x секунд s.t. маркер обновляется, но я бы очень хотел иметь возможность обновлять информацию о положении без обновления. Я знаю, что это можно сделать с помощью перетаскивания, как показано здесь: http://gmaps -samples-v3.googlecode.com / svn / trunk / draggable-markers / draggable-markers.html , но мне нужно знать, как заменить это событие перетаскивания и вместо этого взаимодействовать с python, выдвигая новые координаты. Мне нужен способ получения моей новой информации о координатах на веб-странице. Любая помощь / предложения будут с благодарностью. Единственный класс, действительно применимый к этой проблеме, это GoogleMap. Я не знаком с большим количеством веб-материалов, поэтому чем проще, тем лучше.

что у меня есть:

python -> открывает веб-страницу с автозагрузкой python -> пишет поверх map.html, вставляя новые координаты map.html обновляет, поднимает и отображает новую позицию

что я хочу:

python -> маркер новой позиции {{}} перемещается в новые координаты

import  re
import  sys
import  copy
import  time
import  threading
import  Queue
import  serial
import  webbrowser
import  traceback
import  random
import  math
import  turtle
from    pprint         import pprint
from    collections    import OrderedDict

class MockIo(object):

    def __init__(self):
        pass

    def read(self,buff):
        lat = str(random.random())[2:6]
        lon = str(random.random())[2:6]
        return "$GPGGA,172307.000,3913.%s,N,07716.%s,W,2,10,0.8,199.9,M,-33.4,M,3.8,0000*46\r\n" % (lat,lon)

    def write(self,buff):
        pass

class GPSTurtle(object):

    def __init__(self, new_x = 0, new_y = 0):
        self.t = turtle.Turtle()
        self.x_coord = new_x
        self.y_coord = new_y

        self.diff_x  = 0
        self.diff_y  = 0
        self.heading = 0
        self.origin_x = 0
        self.origin_y = 0

    def initialize_origin(self, new_x, new_y):
        self.origin_x = self.origin_x - new_x
        self.origin_y = self.origin_y - new_y

    def __update_pos(self, new_x, new_y):
        new_x       += self.origin_x
        new_y       += self.origin_y
        new_x *= 20
        new_y *= 20
        self.diff_x  = new_x - self.x_coord
        self.diff_y  = new_y - self.y_coord
        if 0 == self.diff_x:
            if self.diff_y > 0:
                self.heading = 90
            elif self.diff_y < 0:
                self.heading = 270
        elif 0 == self.diff_y:
            if self.diff_x > 0:
                self.heading = 0
            elif self.diff_x < 0:
                self.heading = 180
        else:
            self.heading = math.degrees(math.atan(float(self.diff_y)/float(self.diff_x)))
            if self.diff_x < 0:
                self.heading += 180
            elif self.diff_y < 0:
                self.heading += 360

        self.set_pos(new_x, new_y)
        print self.diff_x,self.diff_y,self.heading,self.x_coord,self.y_coord

    def set_pos(self, new_x, new_y):
        self.x_coord = new_x
        self.y_coord = new_y

    def __draw(self):
        self.t.setheading(self.heading)
        self.t.pendown()
        self.t.goto(self.x_coord, self.y_coord)
        self.t.penup()

    def ungps(self, new_x, new_y):
        new_x = int(1000.0 * new_x)
        new_y = int(1000.0 * new_y)
        return (new_x, new_y)

    def update_and_draw(self, new_x, new_y):
        self.__update_pos(new_x, new_y)
        self.__draw()




class GPS(threading.Thread):

    def __init__(self, comport = 'COM15', baud = 4800):
        super(GPS, self).__init__()
        self.GOOD       = True
        self.gpgga_keys =   [
                                'message_id',
                                'utc_time',
                                'lattitude',
                                'n_s_ind',
                                'longitude',
                                'e_w_ind',
                                'pos_fix_ind',
                                'satellites',
                                'hdop',
                                'msl_altitude',
                                'units_1',
                                'geoid_sep',
                                'units_2',
                                # 'age_of_diff_corr', gps does not have this field by default
                                'diff_ref_station_id',
                                'checksum',
                            ]
        self.PSRF103    =   {
                                'name':'$PSRF103',
                                'msg':{'GGA':'00','GLL':'01','GSA':'02','GSV':'03','RMC':'04','VTG':'05'},
                                'mode':{'SetRate':'00','Query':'01'},
                                'rate':{'off':'00','min':'01','max':'255'},
                                'cksumEnable':{'disable':'00','enable':'01'},
                            }
        self.gps_msg_q  = Queue.Queue()
        self.gps_buff   = ""
        try:
            self.gps_com    = serial.Serial(   
                                                comport, 
                                                baud, 
                                                timeout = 1,
                                                parity  = serial.PARITY_NONE,
                                                rtscts  = 0,
                                                xonxoff = 0
                                            )
        except serial.serialutil.SerialException:
            print "Could not open com port, assuming simulation mode and setting"
            print "com object to MockIo"
            self.gps_com = MockIo()

    def enable_all(self):
        m  = self.PSRF103
        for msg in m['msg'].values():
            st = ','.join([m['name'],msg,m['mode']['Query'],m['rate']['on'],m['cksumEnable']['enable']])
            st = self.append_crc(st)
            self.send_msg(st)
        self.gps_com.read(4028)

    def disable_all(self):
        m  = self.PSRF103
        for msg in m['msg'].values():
            st = ','.join([m['name'],msg,m['mode']['Query'],m['rate']['off'],m['cksumEnable']['enable']])
            st = self.append_crc(st)
            self.send_msg(st)
        self.gps_com.read(4028)

    def append_crc(self,st):
        match     = re.compile("\$(.*)")
        crc        = 0

        if match.search(st):
            st = match.search(st).group(1)

        for letter in st:
            crc = crc ^ ord(letter)
        return "$%s*%0.2x\r\n" % (st,crc)

    def run(self):
        self.disable_all()
        while self.GOOD:
            self.send_GPGGA_req()
            time.sleep(2)

    def send_GPGGA_req(self):
        m  = self.PSRF103
        st = ','.join([m['name'],m['msg']['GGA'],m['mode']['Query'],m['rate']['off'],m['cksumEnable']['enable']])
        st = self.append_crc(st)
        self.send_msg(st)

    def parse_msg(self,st):
        '''
            SAMPLE GPGGA MSG
            "$GPGGA,172307.000,3913.7428,N,07716.7474,W,2,10,0.8,199.9,M,-33.4,M,3.8,0000*46\r\n"
        '''
        retVal = (False,None)
        st     = st.rstrip('\r\n')
        parse  = st.split(',')
        if st.startswith('$GPGGA') and len(self.gpgga_keys) == len(parse):
            retVal = (True, OrderedDict(zip(self.gpgga_keys,parse)))
        else:
            pass

        return retVal

    def send_msg(self, st):
        self.gps_com.write(st)
        self.gps_buff = ''.join([self.gps_buff,self.gps_com.read(1024)])
        buffsplit     = re.compile(r'.*?\r\n|.+')
        splt          = buffsplit.findall(self.gps_buff)
        if 0 < len(splt):
            if splt[-1].endswith('\r\n'):
                self.add_list_to_q(splt)
                self.gps_buff = ""
            else:
                self.add_list_to_q(splt[:-1])
                self.gps_buff = splt[-1]

    def add_list_to_q(self,list_):
        for item in list_:
            self.gps_msg_q.put(item,False)

    def get_item_from_q(self, block = True, timeout = 10):
        return self.gps_msg_q.get(block, timeout)

    def convert_lat_lon(self, lat, lon,ns,ew):
        lat = "%f" % (float(lat[:-7]) + (float(lat[-7:])/60.0))
        lon = "%f" % (float(lon[:-7]) + (float(lon[-7:])/60.0))
        if 'S' == ns:
            lat = str(float(lat) * -1.0)
        if 'W' == ew:
            lon = str(float(lon) * -1.0)
        return (lat,lon)




class GoogleMap(object):

    def __init__(self, path = 'map.html'):
        self.path = path
        self.map_html = '''
                            <!DOCTYPE html>
                            <html>
                            <head>
                            <meta http-equiv="refresh" content="5" /> 
                            <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
                            <style type="text/css">
                              html { height: 100% }   body { height: 100%; margin: 0px; padding: 0px }   #map_canvas { height: 100% } </style>
                            <script type="text/javascript"
                                   src="http://maps.google.com/maps/api/js?sensor=true">
                            </script>
                            <script type="text/javascript">
                               function initialize() {
                                   var lat = %s
                                   var lng = %s
                                   var latlng = new google.maps.LatLng(lat,lng);
                                   var myOptions = {
                                       zoom: 13,
                                       center: latlng,
                                       mapTypeId: google.maps.MapTypeId.ROADMAP
                                   };
                                   var map    = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
                                   var marker = new google.maps.Marker({position: latlng, map: map, title: %s });
                               }
                            </script>
                            </head>
                            <body onload="initialize()">
                              <div id="map_canvas" style="width:100%; height:100%"></div>
                            </body>
                            </html>
                        '''

    def write_map(self,lat = '39.229013',long = '-77.445735',marker = '""'):
        new_map_html = self.map_html % ( str(lat), str(long), str(marker).replace('"','') )
        with open(self.path, 'w') as f:
            f.write(new_map_html)

    def launch_browser(self):
        webbrowser.open_new_tab(self.path)



if __name__ == "__main__":
    map = GoogleMap('map.html')
    map.write_map()
    map.launch_browser()

    gps = GPS('COM15',4800)
    gps.start()

    t = GPSTurtle()
    first_update = True

    try:
        while True:
            try:
                st = gps.get_item_from_q(True,2)
                success,gpgga = gps.parse_msg(st)
                if success:
                    lat, lon = gps.convert_lat_lon( gpgga['lattitude'],
                                                    gpgga['longitude'],
                                                    gpgga['n_s_ind'],
                                                    gpgga['e_w_ind'])
                    la,ln = t.ungps(float(lat),float(lon))
                    if first_update:
                        t.initialize_origin(la,ln)
                        first_update = False
                    else:
                        t.update_and_draw(la,ln)

                    map.write_map(lat,lon,'ME!')
                    time.sleep(5)
            except Queue.Empty:
                # pass
                print "Q-Empty"
    except:
        gps.GOOD = False
        gps.join()
        print "\n\nEXITING PROGRAM\n\n"
        traceback.print_exc(file=sys.stdout)

1 Ответ

1 голос
/ 29 декабря 2011

Вместо обновления вы можете настроить краткий опрос ajax - по сути, проверьте свою страницу с конечной точкой, которая возвращает положение маркера каждые несколько секунд.Вот пост, рассказывающий об этом и ссылающийся на учебник: Данные в реальном времени на веб-странице с помощью jQuery

Другой альтернативой может быть установка длинного опроса - оставить страницу открытой для связи сваш сервер ждет обновления.С другой стороны, ваш пользовательский интерфейс будет обновляться сразу после изменения координат.Большим недостатком является то, что это создает значительную нагрузку на ваш сервер, требуя от него открытого соединения.Масштабирование длинных опросов сложнее.

В этом сообщении хорошо обобщены оба варианта: Короткие опросы и Длинные опросы для веб-приложений реального времени?

РЕДАКТИРОВАТЬ:

Вот довольно грубый пример, но он должен дать вам простую структуру для непрерывного обновления lat long.Заранее извиняюсь, так как мой опыт ограничен без использования веб-сервера, я использовал самый простой для настройки - Google SDK для движка приложений.Он поставляется с сервером разработки, который очень прост в установке и запуске.Вот ссылка на SDK: http://code.google.com/appengine/downloads.html

main.py:

#!/usr/bin/env python

import os

from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
from google.appengine.ext.webapp import template

def doRender(handler, page, templatevalues=None):
    path = os.path.join(os.path.dirname(__file__), page)
    handler.response.out.write(template.render(path, templatevalues))

class MainHandler(webapp.RequestHandler):
    def get(self):
        doRender(self, 'template/main.html')


class AjaxHandler(webapp.RequestHandler):
    def get(self):
        self.response.out.write('{ "lat": "1", "long": "1"}')

def main():
    application = webapp.WSGIApplication([('/', MainHandler),
                                          ('/data.js', AjaxHandler)],
                                         debug=True)
    util.run_wsgi_app(application)


if __name__ == '__main__':
    main()

app.yaml:

application: ajaxtest
version: 1
runtime: python
api_version: 1

handlers:
- url: /favicon\.ico
  static_files: favicon.ico
  upload: favicon\.ico

- url: .*
  script: main.py

main.html (поместите его в папку«шаблон» в корневой папке проекта):

<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>

</head>
<body>
<button>Get JSON data</button>
<div></div>
<script type="text/javascript">
var test = 1;

function update(){
    $.getJSON("/data.js",function(data){

    var items = [];
      $.each(data, function(key, val){
        $("div").append(key + ":" + val + " ");
      });
    });
    }

var t=setInterval("update()",1000);

</script>
</body>
</html>

Для ваших целей измените AjaxHandler, чтобы повторно запросить координаты GPS.Также измените $ ("div"). Append (key + ":" + val + "");отправить обновление на карты Google для координат маркера.

Дайте мне знать, если это не поможет или если вам не повезло с витой.Я ухожу с работы сегодня, поэтому должен быть в состоянии посвятить гораздо больше времени.Удачи!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...