楊民峰 孫洪迪
(北京工業(yè)職業(yè)技術學院信息工程學院,北京 100042)
隨著物聯(lián)網(wǎng)技術的發(fā)展及日趨成熟,人們對車輛信息準確把握的需求已經(jīng)不僅僅涉及自身車輛安全、管理的范疇,更與用戶體驗聯(lián)系緊密[1]。目前車輛的定位監(jiān)控系統(tǒng)一般采用C/S模式,用戶需要下載客戶端才能使用。這種傳統(tǒng)的C/S系統(tǒng)通常通過TCP協(xié)議進行通信,利用Socket編程技術實現(xiàn)客戶端與服務器端的雙向通信,這會導致長期占有連接資源[2]。而基于Web的GPS監(jiān)控系統(tǒng),利用HTTP協(xié)議可以實現(xiàn) C/S的雙向通信[3],用戶只需打開瀏覽器,結合在線地圖就能實時查看車輛位置,使用起來更加方便、簡潔。
筆者研究與實現(xiàn)的基于Web的GPS監(jiān)控系統(tǒng),通過在車輛上安裝定制的車載終端,并把車載終端內(nèi)置的唯一編號作為車輛標識,可以實時獲取并在地圖上標注車輛的地理位置,同時可以查詢車輛的行駛速度、方向、里程、油耗等信息。這些功能的實現(xiàn)是在GPS監(jiān)控設備完善的基礎上,結合定位技術和移動通信技術,將車輛的運行狀況等信息及時反饋給系統(tǒng)平臺,系統(tǒng)平臺將獲取的信息進行處理,從而實現(xiàn)車輛的實時信息顯示。該系統(tǒng)分為2個部分:(1)基于北斗/GPS定位的遠程監(jiān)控車載終端機;(2)車輛數(shù)據(jù)處理服務器系統(tǒng)。遠程監(jiān)控車載系統(tǒng)結構圖如圖1所示。
圖1 遠程監(jiān)控車載系統(tǒng)結構圖
該系統(tǒng)設計目的是基于WebSocket技術,設計實現(xiàn)一個B/S架構的、具有高實時性和穩(wěn)定性的車聯(lián)網(wǎng)監(jiān)控系統(tǒng),使用戶能夠通過隨身攜帶的計算機或智能移動設備的Web瀏覽器,隨時掌握車輛的行駛狀況和位置信息。系統(tǒng)Web頁面要實現(xiàn)對車輛的實時監(jiān)控功能,瀏覽器客戶端就需要及時地獲取服務器端最新上傳的車輛數(shù)據(jù)信息,保持客戶端與服務器端的數(shù)據(jù)信息同步[4]。為了保持這種同步性,引入WebSocket服務器推送技術。
遠程監(jiān)控車載終端利用衛(wèi)星定位實時采集車輛位置信息,然后通過4G網(wǎng)絡,使用UDP通信協(xié)議將數(shù)據(jù)傳輸給服務器,服務器端對收到的車輛信息分析處理,得到車輛坐標、行駛速率、行駛狀態(tài)等相關信息,然后利用WebSocket推送技術,在Web頁面中的地圖界面顯示[5]。遠程監(jiān)控車載系統(tǒng)數(shù)據(jù)處理過程圖如圖2所示。
圖2 遠程監(jiān)控車載系統(tǒng)數(shù)據(jù)處理過程圖
遠程監(jiān)控車載終端機負責收集并發(fā)送采集的車輛信息,每個車載終端機內(nèi)置1個唯一編號作為車輛的身份ID。該終端機系統(tǒng)主要負責對接收的數(shù)據(jù)進行響應、處理和控制,通過北斗/GPS模塊,得到車輛的經(jīng)緯度信息,并按通信協(xié)議,每5 ms向數(shù)據(jù)服務器發(fā)送1次數(shù)據(jù)。數(shù)據(jù)包括:車輛編號、車輛經(jīng)度、車輛緯度、車輛速度等信息。遠程監(jiān)控車載終端機包括:電源處理及轉換模塊、衛(wèi)星定位模塊、通信與接口模塊以及數(shù)據(jù)存儲模塊。嵌入式系統(tǒng)硬件功能的實現(xiàn),除了需要基本形式的微控制器、存儲器設備、輸入輸出設備外,還需要能實現(xiàn)不同通信、處理等功能的不同的豐富外設[6]。其中,硬件平臺采用嵌入式系統(tǒng)結構,硬件電路分為北斗兼容型多頻功能模塊和功能底板電路系統(tǒng)(實時接收、分發(fā)、存儲部分及控制2個部分)。硬件框架如圖3所示。
圖3 硬件系統(tǒng)框架圖
2.2.1 UDP服務端
在數(shù)據(jù)處理服務器中,UDP服務端負責接收車輛終端傳回的原始數(shù)據(jù),并對數(shù)據(jù)進行解析處理,臨時保存在 1 個 Map類型的對象中。Java用DatagramSocket 代 表 UDP 協(xié) 議 的 Socket,DatagramSocket本身只是碼頭,不維護狀態(tài),不能產(chǎn)生IO流,它唯一的作用是接收和發(fā)送數(shù)據(jù)報,Java用DatagramPacket代表數(shù)據(jù)報,DatagramSocket接收和發(fā)送的數(shù)據(jù)都是通過DatagramPacket對象完成的[7]。接收端步驟如下:
(1)創(chuàng)建接收端的 Socket對象(Datagram Socket),使用端口 12345:
socket=new DatagramSocket(null);
socket.setReuseAddress(true);
socket.bind(new InetSocketAddress(12345));//端口號 12345
(2)創(chuàng)建1個數(shù)據(jù)包,用于接收數(shù)據(jù):
byte[]data=new byte[1024];
packet=new DatagramPacket(data,data.length);
(3)調(diào)用DatagramSocket類中的receive方法接收數(shù)據(jù):
socket.receive(packet);
(4)解析數(shù)據(jù)包,轉換為字符串數(shù)據(jù):
String info=new String(packet.getData(),0,packet.getLength());
(5)進一步解析包含小車信息的字符串,把數(shù)據(jù)存放在Map類型的對象clientMap中:
CarMsgPojo carMsgPojo=MsgUtil.msgDealWith(info);
Constant_Class.clientMap.put(String.valueOf(carMsgPojo.getCar()),carMsgPojo);
其中,MsgUtil.msgDealWith()方法對包含車輛信息的json字符串進行拆分,對原始車輛經(jīng)緯度數(shù)據(jù)進行屏幕像素化處理,使經(jīng)緯度轉換為屏幕地圖對應的像素位置,轉換步驟如下:
(1)按顯示屏幕分辨率像素比例截取地圖上區(qū)域。
(2)記錄地圖上截圖區(qū)域左上角經(jīng)度值和緯度值,右下角經(jīng)度值和緯度值。
(3)計算當前車輛經(jīng)度值和左上角經(jīng)度值的差,得出占多少個經(jīng)度lon。
(4)計算當前車輛緯度值和左上角緯度值的差,得出占多少個緯度lat。
(5)計算地圖在屏幕滿屏狀態(tài)下每個經(jīng)度、緯度在當前分辨率下占多少像素,分別記為x,y。
x=屏幕橫向x軸像素/(右上角經(jīng)度-左上角經(jīng)度)
y=屏幕縱向y軸像素/(左上角緯度-左下角緯度)
(6)計算車輛當前在屏幕上的像素位置:
(lon*x,lat*y)
可以加上糾偏參數(shù),修正屏幕顯示位置:
lon=lon*x+offset_x;
lat=lat*y+offset_y;
部分代碼如下:
//計算GPS坐標到屏幕圖像的像素位置-start
Properties properties=new Properties();
try{
//使用ClassLoader加載 properties配置文件生成對應的輸入流
InputStream in=MsgUtil.class.getClass Loader () getResourceAsStream ("coordinate.properties");
properties.load(in);
//獲取截取的地圖邊界經(jīng)緯度
String longitude_left_top=properties.getProperty("longitude_left_top");
String latitude_left_top =properties.getProperty("latitude_left_top");
//當前經(jīng)度和左上角經(jīng)度差
lon=(lon-Double.parseDouble(longitude_left_top));//經(jīng)度 左上角經(jīng)度
//當前緯度和左上角緯度差
lat=(Double.parseDouble(latitude_left_top)-lat);//緯度 左上角緯度
//計算滿屏下每個經(jīng)度,緯度在當前分辨率下占多少像素
String longitude_right_top=properties.getProperty("longitude_right_top");
String latitude_left_down=properties.getProperty("latitude_left_down");
String screenresolution_x=properties.getProperty("screenresolution_x");
String screenresolution_y=properties.getProperty("screenresolution_y");
double
x=Double.parseDouble(screenresolution_x)/(Double.parseDouble(longitude_right_top)-Double.parseDouble(longitude_left_top));
double
y=Double.parseDouble(screenresolution_y)/(Double.parseDouble(latitude_left_top)-Double.parseDouble(latitude_left_down));
//加上糾偏,得出經(jīng)緯度在屏幕地圖上的像素位置
int offset_x=Integer.parseInt(properties.getProperty("offset_x"));
int offset_y=Integer.parseInt(properties.getProperty("offset_y"));
lon=lon*x+offset_x;
lat=lat*y+offset_y;
}catch(IOException e){
e.printStackTrace();
}
//----------計算GPS坐標到屏幕圖像的像素位置--end------------
其中,配置文件coordinate.properties內(nèi)容如下:
#截取的地圖圖片左上角GPS坐標
longitude_left_top=116.125763
latitude_left_top=39.967256
#截取的地圖圖片右上角GPS坐標
longitude_right_top=116.131148
latitude_right_top=39.967256
#截取的地圖圖片左下角GPS坐標
longitude_left_down=116.125763
latitude_left_down=39.964678
#當前屏幕分辨率
screenresolution_x=1680
screenresolution_y=1050
#糾偏,根據(jù)實際頁面效果,調(diào)整在頁面上對應的像素位置
offset_x=-3
offset_y=-5
2.2.2 W ebSocket服務端
UDP服務和WebSocket服務共享clientMap對象,UDP服務把車輛數(shù)據(jù)存入map對象中,一旦瀏覽器客戶端和服務器建立WebSocket連接,服務端每隔500 ms把map對象中的數(shù)據(jù)推送到Web頁面端。
服務端部分代碼如下:
@ServerEndpoint(value="/clinetWebSocket")
@Component
public classWebSocketServer{
static{
new Thread(()->{
Map<String,CarMsgPojo>map=Constant_Class.clientMap;
while(true){
if(getOnlineCount()>0&&map.size()>0){
String jsonString =JSONObject.toJSONString(map);
try{
send InfoAll(jsonString);//500 ms推送1次
Thread.sleep(500);}catch(Exception ee){}
}
}
})start();
}
2.2.3 車輛數(shù)據(jù)W eb頁面可視化顯示
在該系統(tǒng)中設計index.jsp頁面作為車輛位置顯示頁面,在頁面中事先放入1張按顯示器分辨率比例裁剪好的靜態(tài)地圖圖片作為背景;在index.jsp頁面中引入index.js腳本文件,index.js負責接收服務端推送的車輛信息,在index.js中創(chuàng)建map對象,連接WebSocket服務端,接收到服務端推送過來的json數(shù)據(jù)(json數(shù)據(jù)中包含了每個車輛的信息,其中,車輛的GPS數(shù)據(jù)是處理過后的屏幕像素位置)。
其中carGps()函數(shù)遍歷map對象。若車輛信息不存在,則添加到map中,同時在頁面中新增顯示車輛標志的div層;若已經(jīng)存在,則更新最新車輛數(shù)據(jù);最后遍歷map對象數(shù)據(jù),通過設置每個車輛div樣式的top和left屬性,實現(xiàn)車輛在Web頁面端的定位,如圖4所示。代碼如下:
圖4 車輛實時定位顯示效果
function carGps(msg){
var data=$.parseJSON(msg);
var carid=0;
var cardiv=null;
$.each(data,function(key,obj){
if(maps.get(key)==null){//如果 map里沒有
maps.set(key+’’,obj);
addCar(maps.get(key));
}else{
maps.set(key+’’,obj);
}
});
maps.forEach(function(obj1){
var lat=obj1.lat;//經(jīng)度
var lon=obj1.lon;//緯度
$("#"+obj1.car).css({top:parseInt(lat),left:parseInt(lon)})
});
}
其中,addCar()函數(shù)在頁面中添加1個車輛圖標,實現(xiàn)可視化效果,代碼如下:
function addCar(data){
var cardiv=$('<div id="'+data.car+'"></div>');//創(chuàng)建 1個 cardiv
cardiv.addClass('carDiv'); //添加 css樣式
cardiv.css({top:parseInt(data.lat),left:parseInt(data.lon)})
var car=$('<div class="car"></div>');//創(chuàng)建1個 car
car.appendTo(cardiv);
var carp=$('<p>'+data.car+'</p>');//創(chuàng)建1個顯示車輛的cardiv
carp.appendTo(cardiv);
cardiv.appendTo('#index');
}
針對車輛的實時監(jiān)控問題,筆者提出并設計實現(xiàn)了一個基于Web瀏覽器的車輛監(jiān)控系統(tǒng)。搭建該系統(tǒng)基于Web的GPS監(jiān)控系統(tǒng)環(huán)境,成本較低,通過在車輛上安裝車載終端,可同時在多處Web瀏覽器上實時監(jiān)控多個車輛,執(zhí)行速度較快,安全性較高,且Web界面顯示操作簡單方便,易于被大眾所接受。由于標識車輛需要通過車載終端的唯一編號確定,此系統(tǒng)更適用于固定場地的車輛監(jiān)控,如景區(qū)、學校等場所的游覽車、巡邏車的監(jiān)控,具有很好的市場前景。