2011-12-28 67 views
1

我有一个Arduino w/GPS芯片,处理NMEA字符串w/python。我有一个HTML文件,我打开并自动刷新每x秒s.t.标记更新,但我真的希望能够更新位置信息,而无需刷新。我知道这可以在这里演示:http://gmaps-samples-v3.googlecode.com/svn/trunk/draggable-markers/draggable-markers.html,但我需要知道如何替换该拖动事件,而不是界面瓦特/ python推出新的坐标。我需要一种让我的新坐标信息进入网页的方式。任何帮助/建议将不胜感激。唯一真正适用于这个问题的是GoogleMap。我不熟悉w /很多网页的东西,所以越简单越好。根据gps coords更新google地图位置

我有什么:

蟒蛇 - >打开网页W /自动重 蟒蛇 - >过map.html令状在新COORDS map.html刷新堵塞和拾取并显示新的位置

什么我想:

蟒 - >新位置{{}}标记移动到新COORDS

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

Inste做刷新的广告,你可以设置ajax短轮询 - 基本上你的页面检查结束点每隔几秒就会返回一次标记的位置。这里有一篇文章讨论它并链接到教程:Real-time data on webpage with jQuery

另一种方法是设置一个长轮询 - 让页面与您的服务器保持开放连接等待更新。最重要的是,只要坐标发生变化,用户界面就会更新。最大的缺点是这会给服务器带来相当大的负载,要求它保持开放的连接。缩放长轮询更困难。

这篇文章总结了这两个选项得好:Short-polling vs Long-polling for real time web applications?

编辑:

这里是一个非常粗略的例子,但它应该给你一个简单的框架,不断更新LAT长。提前道歉,因为我的经验是有限的,没有使用网络服务器,我用最简单的设置,我可以想到 - 谷歌应用程序引擎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地图发送标记坐标的更新。

让我知道如果这没有帮助,或者如果你没有扭曲的运气。我今天下班了,所以应该能够投入更多的时间。祝你好运!

+0

是否可以在不设置Web服务器的情况下执行此操作。我没有网络体验,我希望有一种方法可以通过查看文件系统或其他方式来实现。即使这个例子http://stackoverflow.com/questions/333664/simple-long-polling-example-code似乎比我需要的方式更多。 – pyInTheSky 2011-12-29 03:18:47

+0

有没有简单的方法来说,泵出一个带有样本#和lat/long的json文件,并有一个简单的ajax/jscript文件来读取文件,嘿,我有一套新的坐标系,更新地图标记? – pyInTheSky 2011-12-29 03:21:46

+0

我发现http://www.html5rocks.com/en/tutorials/file/dndfiles/看起来像它可以用来读取本地文件系统文件。如果是这样的话,我只是不知道如何将html5的'代码'与javascript接口 – pyInTheSky 2011-12-29 03:23:47

相关问题