Pythonおもしろくなってきたかも

20080730

ぶっちゃけていうと、素のままではできることが少なく、最初からいろんな関数があたえられてるPHPと比べると大変なんだけど、シンプルさとソースの見やすさから好きになりそうな言語。わかりやすいし。

それで、GPSとのシリアル通信のプログラムなんだけど、
今まで readline() で読んでたところを、timeout値を1秒近辺(後述)にし read() で取ってやるとつまりもなく、非常にスムース

GPSからの出力データは1秒おきにどばっとくる。そこで、timeout値は0.9秒にしてやって、データがシンクロできるようにとPythonの計算時間を考慮して、一定のコンマ秒で read() する時間を逐次調節するように

ソースは以下の通り

#!/usr/bin/python

import sys, os, os.path, serial, urllib, urllib2, socket, thread, time

socket.setdefaulttimeout(10)

serialPort = 'COM6' #EeePC usb
#serialPort = 'COM3' #EeePC bluetooth
url = 'hogehoge'

tryCount = 0
baseTime = 0

def getGprmcSentence():
    global baseTime

    while True:
        try :
            buffer = ser.read(1000)
        except :
            print "error"
            return "error"

        if int(time.time()) + baseTime - time.time() > 0:
            time.sleep(int(time.time()) + baseTime - time.time() )

        if buffer[0:6] != '$GPGGA':
            print 'sync...'+"\n"
            time.sleep(0.1)
            if baseTime > 0.9:
                baseTime -= 0.9
            else:
                baseTime += 0.1

        if buffer[12:13] == '0':
            lines = buffer.split("\r\n")
            data = []

            for line in lines:
                nmea = line.split(',')

                if nmea[0] == '$GPGGA':
                    if len(nmea) == 15 and nmea[14][0:1] == '*':
                        data.append(nmea[9])
                elif nmea[0] == '$GPRMC':
                    if len(nmea) == 13 and nmea[12][1:2] == '*':
                        data.append(nmea[3])
                        data.append(nmea[5])
                        data.append(nmea[7])
                        data.append(nmea[8])
                        data.append(nmea[9])
                        data.append(nmea[1])

            args = (data,)
            print "thread start..."
            thread.start_new_thread(putGpsData, args)

def putGpsData(args) :

    global tryCount

    params = {
        "date" : args[5],
        "time" : args[6],
        "latitude" : args[1],
        "longitude" : args[2],
        "altitude" : args[0],
        "speed" : args[3],
        "heading" : args[4],
    }

    try:
        urllib2.urlopen(url, urllib.urlencode(params))
    except urllib2.HTTPError, e:
        print e

    tryCount = tryCount+1

    print tryCount
    print args
    print "\n"

def connect() :
    global ser, baseTime

    try:
        ser = serial.Serial(serialPort, 38400, bytesize=8, parity='N', stopbits=1, timeout=0.9, xonxoff=0, rtscts=0)
    except serial.SerialException, e:
        print e

    baseTime = time.time() - int(time.time());

    while True:
        temp = getGprmcSentence()
        if temp == "error":
            ser.close()
            return

    ser.close()

while True:
    connect()
    time.sleep(5)
    print "reconnect..."

んで、あとはGPSのデータから読み取ったデータにおいて10秒おきにスレッドでPUTしてやる。

そのPUTもhttpのタイムアウト値が10秒以上超してしまうと、整合性があわなくなるので、httpのタイムアウト値も10秒に設定

以前は、NMEAフォーマットのRMCセンテンスだけしかとってなかったので高度が取得できなかったけど、GGAセンテンスも読み取って高度をゲットや!

最後に、USBやBluetoothが途中に抜かれたり、通信エラーしても復帰できるように例外処理からsleep()かけて5秒後に復帰処理するように

PHPのほうは、Ajaxによる更新時間とGPSデータの更新時間が近すぎるとタイミングによってデータの2重取得や取得逃しが発生するので、GPSデータの更新時間から5秒後に更新する(実際にはサーバ時間で秒数の一桁が5秒のとき・・・サーバ時間が正しいことが前提だけどね)ように初回Ajax更新時間を調節

いろんなところにいって早く試したいなw