一個小項目,做點總結。
項目需求
本項目爲從串口讀取GPS/北斗設備接收數據,進行處理後使用百度地圖api實時顯示定位。
解決辦法
這裏有幾個關鍵的信息,需要一步一步進行實現。
串口
串口通信這裏就不做介紹。本意是使用百度地圖的api,但是這是一個靜態的網頁。如果要動態顯示,且由前端直接讀取PC端的串口數據其實不好實現,在網上查了很多資料,最通常的做法是在前端使用一個active控件讀取串口的數據。這樣有缺點,一是技術過於老套,只兼容IE,其他瀏覽器就不行;二是怎麼做到動態實時定位呢?這個沒有想明白。放棄了從前端直接讀取PC串口的想法。還是需要去用後臺採集數據,搭建後臺和前端進行通信。
串口模擬
路是一步一步走的,胖子也是一口一口吃的,直接去讀取GPSS/北斗設備的數據是不可行的。 先採用電腦端的串口助手進行數據的發送和接收。
- 首先採用VSPD(很著名)在PC端模擬出一懟串口,再使用某個串口助手實現數據的發送和接收顯示。串口助手很多,隨便選擇一種即可。
- 這樣就可以保證有可靠的數據發送和接收的通信是沒有問題的。保證發送端數據的一直髮送,接着用程序去讀取串口的數據。 #語言版本:Python3 #依賴庫:serial,pyserial #串口助手發送數據:108.111,34.111 import serial from time import sleep if __name__ == '__main__': serial = serial.Serial('COM2', 115200)#根據自己模擬的端口確定com if serial.isOpen() : print("open success") else : print("open failed") while True: n = serial.inWaiting() if n: data= str(serial.read(n))[2:-1].split(',')#對讀取的數據進行簡單的處理 j = data[0] w = data[1] print(data)
讀取串口
保證程序可以正確的讀取發送的數據後,再去處理真實的數據,開啓GPS/北斗設備,將USB插在電腦上,開始讀取原始數據。原始數據包含的信息比較多,而且發送頻率也比較高,數據眼花繚亂,這裏只匹配想要的數據進行處理。在百度地圖上定位只需要“經度”、“緯度”。(這裏牽扯到一個座標系的轉換,後面說),這是一個Ajax的程序:
def ajax_list(request): s = serial.Serial('COM5', 115200) #定義接收數據的次數 l = 0 data=[] while True: line = str(str(s.readline())[2:]) # print(line)#原始數據 if line.startswith('$GNGGA'):#只匹配以“$GNGGA”開頭的數據 line=str(line).split(',') # print("接收的數據:"+ str(line)) # print("OK:"+str(line)) # print("指令名稱: ", line[0]) # print("發送時間: ", line[1][:6]) # 經緯度轉換 #經度數據處理 j = float(line[4][:-7])+float(line[4][-7:])/60 #緯度數據處理 w = float(line[2][:-7])+float(line[2][-7:])/60 #時間 gpstime=time.strftime('%H:%M:%S',time.localtime(time.time())) # id global l l= l + 1 # 添加數據 data.append(j) data.append(w) data.append(l) data.append(gpstime) print(data) return HttpResponse(json.dumps(data), content_type='application/json')
百度地圖api
先去申請百度地圖api 的 key。然後看這裏:http://lbsyun.baidu.com/jsdemo.htm#i8_4 這裏放出百度地圖定位aip的源碼:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="viewport" content="initial-scale=1.0, user-scalable=no" /> <style type="text/css"> body, html{width: 100%;height: 100%;margin:0;font-family:"微軟雅黑";} #allmap{height:500px;width:100%;} #r-result{width:100%; font-size:14px;} </style> <script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=您的密鑰"></script> <title>城市名定位</title> </head> <body> <div id="allmap"></div> <div id="r-result"> 經度: <input id="longitude" type="text" style="width:100px; margin-right:10px;" /> 緯度: <input id="latitude" type="text" style="width:100px; margin-right:10px;" /> <input type="button" value="查詢" onclick="theLocation()" /> </div> </body> </html> <script type="text/javascript"> // 百度地圖API功能 var map = new BMap.Map("allmap"); map.centerAndZoom(new BMap.Point(116.331398,39.897445),11); map.enableScrollWheelZoom(true); // 用經緯度設置地圖中心點 function theLocation(){ if(document.getElementById("longitude").value != "" && document.getElementById("latitude").value != ""){ map.clearOverlays(); var new_point = new BMap.Point(document.getElementById("longitude").value,document.getElementById("latitude").value); var marker = new BMap.Marker(new_point); // 創建標註 map.addOverlay(marker); // 將標註添加到地圖中 map.panTo(new_point); } } </script>
上面的程序是靜態的,項目需求把從串口源源不斷讀取的數據在百度地圖上進行顯示。這裏想到使用了Ajax。
Ajax
Ajax 即“Asynchronous Javascript And XML”(異步 JavaScript 和 XML),是指一種創建交互式網頁應用的網頁開發技術。 Ajax = 異步 JavaScript 和 XML(標準通用標記語言的子集)。 Ajax 是一種用於創建快速動態網頁的技術。 Ajax 是一種在無需重新加載整個網頁的情況下,能夠更新部分網頁的技術。 通過在後臺與服務器進行少量數據交換,Ajax 可以使網頁實現異步更新。這意味着可以在不重新加載整個網頁的情況下,對網頁的某部分進行更新。 傳統的網頁(不使用 Ajax)如果需要更新內容,必須重載整個網頁頁面。
Django
使用的是Python語言,用Django後臺框架就很簡單,這裏推薦一個博客,學習到很多。自強學堂-Django教程 花了點時間學習了下,Django還是很容易上手的最後將接收到處理的數據存儲爲csv文件。 這裏給出本項目的Django和前端的程序。
view.py
from django.http import HttpResponse from django.shortcuts import render import json import serial import time import csv from time import sleep def ajax_list(request): data=[] while True: line = str(str(s.readline())[2:]) # print(line) if line.startswith('$GNGGA'): line=str(line).split(',') # print("接收的數據:"+ str(line)) # print("OK:"+str(line)) # print("指令名稱: ", line[0]) # print("發送時間: ", line[1][:6]) # 經緯度轉換 j = float(line[4][:-7])+float(line[4][-7:])/60 w = float(line[2][:-7])+float(line[2][-7:])/60 #時間 gpstime=time.strftime('%H:%M:%S',time.localtime(time.time())) # id global l l= l + 1 # 添加數據 data.append(j) data.append(w) data.append(l) data.append(gpstime) print(data) with open('./rec_gps.csv','a',newline='') as csvFile1: writer = csv.writer(csvFile1) writer.writerow((l,gpstime,j,w)) csvFile.close() return HttpResponse(json.dumps(data), content_type='application/json') s = serial.Serial('COM5', 115200) global l l = 0 csvFile = open('./rec_gps.csv', 'a',encoding = 'utf-8',newline='') writer = csv.writer(csvFile) writer.writerow(('id','time','longitude','latitude'))
index.html
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="viewport" content="initial-scale=1.0, user-scalable=no" /> <style type="text/css"> body, html{width: 100%;height: 100%;margin:0;font-family:"微軟雅黑";} /* #allmap{height:500px;width:100%;} #r-result{width:100%; font-size:14px;} */ #allmap{float: right;height:100%;width:80%;} #r-result{float: left;height:80%;width:20%; overflow:auto;text-align: center} #list{position:fixed;top:-16px;} #title{position:fixed;top:5px;} </style> <script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=這裏寫你申請的百度地圖api的key"></script> <script src="http://apps.bdimg.com/libs/jquery/1.11.1/jquery.min.js"></script> <!-- WGS84轉BD09 start--> <script src="https://unpkg.com/gcoord/dist/gcoord.js"></script> <!-- end --> <title>經緯度定位</title> </head> <!-- 框架測試start --> <!-- end --> <body> <div id="allmap"></div> <div id="r-result"> <div id="list"> <p style="background-color:rgb(0, 255, 221)">經緯度數據(WGS84座標)</p> </div> <div id = "title" > <p style="background-color:rgb(0, 255, 221)">ID | Time | Longitude | Latitude</p> </div> <p> </p> <div id="list_result" style="font-size: 90%"></div> </div> </body> </html> <script type="text/javascript"> // 百度地圖API功能 var map = new BMap.Map("allmap"); map.centerAndZoom(new BMap.Point(108.953445,34.265721),15); map.enableScrollWheelZoom(true); $(document).ready(function(){ // 列表 list $('#list').click(function(){ $.getJSON('/ajax_list/',function(ret){ // $('#list_result').append(ret[2]+", "+ret[3]+", "+ret[0].toFixed(6)+", "+ret[1].toFixed(6) +"<br />"); // $('#list_result').append("緯度:" + ret[1]+"<br />" ); // WGS84座標 var result = gcoord.transform( [ret[0], ret[1]], // 經緯度座標 gcoord.WGS84, // 當前座標系 gcoord.BD09 // 目標座標系 ); //BD09座標 var longitude = result[0]; var latitude = result[1]; var id map.clearOverlays(); var new_point = new BMap.Point(longitude,latitude); var marker = new BMap.Marker(new_point); // 創建標註 map.addOverlay(marker); // 將標註添加到地圖中 map.panTo(new_point); document.getElementById("longitude").innerHTML=longitude; document.getElementById("latitude").innerHTML=latitude; // $('#list_result').append("經度:" + ret[0]+"<br />" ); // $('#list_result').append("緯度:" + ret[1]+"<br />" ); }) }) }); </script> <!-- # 自動點擊按鈕js --> <script type="text/javascript"> function myrefresh(){ document.getElementById('list').click(); } setInterval("myrefresh()","2000"); </script>
urls.py
from django.urls import path from gps import views as gps_views from django.contrib import admin urlpatterns = [ path('', gps_views.index), path('ajax_list/', gps_views.ajax_list) ]
Run_me.bat
批處理文件,方便不懂Django的人開啓服務
@echo on python3 .\manage.py runserver cmd /k