摘要:為了解決由汽車而引起的能源、環(huán)境和安全問題,進(jìn)行了車聯(lián)網(wǎng)的PC機(jī)監(jiān)控中心以及Android手機(jī)客戶端的研究與設(shè)計(jì)。完成了PC機(jī)的Socket通信、電子地圖的加載與糾偏、后臺數(shù)據(jù)庫的設(shè)計(jì)。同時(shí)也完成了在Android操作系統(tǒng)下Socket通信和地圖的加載與糾偏問題。與硬件平臺進(jìn)行聯(lián)合測試,驗(yàn)證了監(jiān)控中心和手機(jī)客戶端設(shè)計(jì)的有效性,且具有良好的魯棒性。本文網(wǎng)絡(luò)版地址:http://www.eepw.com.cn/article/245925.htm
關(guān)鍵詞:車聯(lián)網(wǎng);socket通信;地圖糾偏;Android系統(tǒng)
DOI: 10.3969/j.issn.1005-5517.2014.4.003
引言
隨著汽車行業(yè)的快速發(fā)展,全球能源問題、環(huán)境問題和安全問題日益嚴(yán)重,解決問題的方式之一是建立汽車移動(dòng)物聯(lián)網(wǎng)通信平臺。汽車移動(dòng)物聯(lián)網(wǎng)分為感知層、網(wǎng)絡(luò)層和應(yīng)用層三層。由感知層獲取采集車輛內(nèi)部和外部的各種信息。網(wǎng)絡(luò)層主要是GPRS/3G無線網(wǎng)絡(luò),將感知層得到的信息通過GPRS/3G無線網(wǎng)絡(luò)發(fā)送到上位機(jī),應(yīng)用層主要是接收網(wǎng)絡(luò)層傳輸過來的數(shù)據(jù)并進(jìn)行處理[1],圖1為車聯(lián)網(wǎng)三層架構(gòu)圖。
系統(tǒng)的應(yīng)用層包括上位機(jī)監(jiān)控中心和Android手機(jī)版本的客戶端,具備六大功能模塊:車輛基本信息、遠(yuǎn)程監(jiān)控、遠(yuǎn)程控制、遠(yuǎn)程故障診斷、尋車輔助、駕駛員疲勞狀態(tài)等。
上位機(jī)監(jiān)控中心作為Socket服務(wù)器,要求具備公網(wǎng)IP和端口,可以被外網(wǎng)訪問。車載終端模塊作為Socket客戶端,當(dāng)Socket連接建立之后,由車載終端將車輛的信息通過GPRS無線網(wǎng)絡(luò)傳給PC機(jī),同時(shí)上位機(jī)監(jiān)控中心也可以主動(dòng)下發(fā)一些指令,查詢車載終端的狀態(tài),要求車載終端上傳相關(guān)信息。
1 PC機(jī)監(jiān)控中心設(shè)計(jì)
1.1 Socket通信設(shè)計(jì)
Socket分為服務(wù)器和客戶端兩部分,上位機(jī)作為服務(wù)器,使用VB中的Winsock控件,通過Socket實(shí)現(xiàn)與車載終端和手機(jī)客戶端的通信。
服務(wù)器端Winsock在接收客戶端連接之后,會(huì)檢測Winsock1.State的值,如果Winsock1沒有關(guān)閉的話則會(huì)將Winsock1關(guān)閉。當(dāng)服務(wù)器與客戶端連接成功之后,服務(wù)器便開始接收客戶端的數(shù)據(jù)并且進(jìn)行處理,同時(shí)還可以向客戶端發(fā)送數(shù)據(jù)和命令。
當(dāng)打開了主窗體時(shí),在Private Sub Form_Load()事件中自動(dòng)加載Socket的監(jiān)聽和連接,并且當(dāng)點(diǎn)擊了各個(gè)功能模塊的按鈕時(shí),上位機(jī)會(huì)通過Socket向車載終端下發(fā)查詢或者控制指令。
在PC機(jī)上位機(jī)程序中,需要設(shè)計(jì)兩個(gè)Socket連接,一個(gè)是用來與車載終端建立連接,另外一個(gè)是用來與Android手機(jī)建立連接。上位機(jī)Winsock1收到車載終端發(fā)送的數(shù)據(jù)之后,會(huì)進(jìn)行處理并且存入到后臺數(shù)據(jù)庫。Android手機(jī)通過Winsock2從上位機(jī)獲取數(shù)據(jù)。當(dāng)多個(gè)車載終端同時(shí)連接監(jiān)控中心時(shí),可以采用動(dòng)態(tài)加載和卸載Winsock的方式,同一個(gè)端口監(jiān)聽不同的連接請求,根據(jù)客戶端的IP地址來區(qū)分車載終端,端口號相同但連接的Index不同。
1.2 電子地圖的加載與糾偏
為了能夠在電腦上直觀地看到車輛的位置,在上位機(jī)設(shè)計(jì)了一個(gè)地圖加載界面,通過GPRS傳送的經(jīng)度和緯度信息,顯示出車輛的當(dāng)前位置。由于傳統(tǒng)的地理信息系統(tǒng)(GIS)技術(shù)復(fù)雜,建設(shè)和維護(hù)的成本高,本次設(shè)計(jì)采用調(diào)用在線地圖API(應(yīng)用程序接口)的方式來實(shí)現(xiàn)地圖的加載,這樣一方面省去了繁瑣的測繪和地圖編制工作,另一方面也保證了地圖更新的實(shí)時(shí)性,地圖提供商會(huì)定期更新地圖,提高定位的有效性和精度[2]。
通過VB中的webbrowser控件,來加載一個(gè)后綴名為.htm的靜態(tài)網(wǎng)頁文件,可以實(shí)現(xiàn)電子地圖的加載。在靜態(tài)網(wǎng)頁中,編寫一個(gè)JavaScript函數(shù),就可以在百度地圖上通過經(jīng)度和緯度進(jìn)行定位,并且可以實(shí)現(xiàn)電子地圖的放大、縮小和移動(dòng)。
由于GPS的坐標(biāo)與百度地圖加載的坐標(biāo)是不匹配的。國際上采用的是WGS-84標(biāo)準(zhǔn)的地心坐標(biāo),國內(nèi)發(fā)行的地圖必須要使用國家測繪局規(guī)定的GCJ-02進(jìn)行加密,而百度地圖在此基礎(chǔ)上還使用百度公司的BD-09進(jìn)行二次加密,因此GPS采集的經(jīng)緯度和百度地圖并不匹配,需要進(jìn)行坐標(biāo)接口轉(zhuǎn)換,百度地圖也提供了進(jìn)行坐標(biāo)轉(zhuǎn)換的API接口函數(shù)。
在VB中利用webbrowser控件調(diào)用電子地圖并且實(shí)現(xiàn)坐標(biāo)轉(zhuǎn)換的語句如下:
We b B r o w s e r 1 . D o c u m e n t . parentWindow.execScript \"map. panTo(new BMap.Point( \" jingdu \",\" weidu \"))\", \"javascript\"
We b B r o w s e r 1 . D o c u m e n t . parentWindow.execScript\"map. addOverlay(new BMap.Marker(new BMap.Point( \" jingdu \",\" weidu \")))\", \"javascript\"
We b B r o w s e r 1 . D o c u m e n t . parentWindow.execScript \"BMap. Convertor.translate(new BMap. Point( \" jingdu \",\" weidu \"),0,translateCallback)\", \"javascript\"
在上面的語句中,使用WebBrowser1.Navigate App.Path \"\BaiduMap.htm\"這個(gè)語句來加載已經(jīng)編寫好的“BaiduMap.htm”地圖文件。調(diào)用坐標(biāo)轉(zhuǎn)換函數(shù)時(shí)使用了new BMap.Point函數(shù)來新建坐標(biāo)點(diǎn),translateCallback為在靜態(tài)網(wǎng)頁文件中編寫的函數(shù),該函數(shù)可以實(shí)現(xiàn)將指定點(diǎn)移到地圖中心、清除標(biāo)注以及在指定坐標(biāo)位置添加地標(biāo)[3]。
1.3 后臺數(shù)據(jù)庫的設(shè)計(jì)
在VB中可以直接嵌入開發(fā)Access數(shù)據(jù)庫,通過“外接程序”中的“可視化數(shù)據(jù)管理器”可以直接創(chuàng)建Access數(shù)據(jù)庫,也可以加載或?qū)肫渌愋偷臄?shù)據(jù)庫。在VB中與數(shù)據(jù)庫的連接通常是使用ADO來實(shí)現(xiàn)的,在VB中操作后臺數(shù)據(jù)庫的步驟如下[4]:
(1)創(chuàng)建或?qū)霐?shù)據(jù)庫,與數(shù)據(jù)庫建立連接。
(2)根據(jù)相應(yīng)的命令讀取數(shù)據(jù)庫中的數(shù)據(jù),并且在數(shù)據(jù)綁定控件中顯示。
(3)對獲取的對象進(jìn)行增刪改查操作,并且將更新后的數(shù)據(jù)重新存入數(shù)據(jù)庫。
在數(shù)據(jù)庫的表格中,設(shè)計(jì)的字段主要有車主、車牌號、車型、經(jīng)度、緯度、速度、前左車門、前右車門、后左車門、后右車門、前端蓋、后端蓋、故障代碼和駕駛員疲勞狀態(tài)等,在收到了GPRS發(fā)送過來的數(shù)據(jù)之后,根據(jù)協(xié)議進(jìn)行解碼,將其中的數(shù)據(jù)分別存入對應(yīng)的數(shù)據(jù)庫當(dāng)中。向數(shù)據(jù)庫中新增數(shù)據(jù)的代碼如下:
Adodc1.Recordset.AddNew ’將數(shù)據(jù)寫入數(shù)據(jù)庫
Adodc1.Recordset(\"車主\") = chezhu
Adodc1.Recordset(\"車牌號\") = chepaihao
Adodc1.Recordset(\"車型\") = chexing
. . . . . .
Adodc1.Recordset.Update
上面的chezhu、chepaihao、chexing等變量都是獲得了車載終端數(shù)據(jù)的全局變量,利用這種方式可以將數(shù)據(jù)存入到數(shù)據(jù)庫對應(yīng)的字段當(dāng)中,便于查詢、使用和保存。
2 Android手機(jī)客戶端設(shè)計(jì)
2.1 Android中Socket通信設(shè)計(jì)
Android中提供了一個(gè)Socket的類,存在于“java. net.Socket”包中。首先要設(shè)定連接服務(wù)器的公網(wǎng)IP以及端口號,同時(shí)以輸入流InputStream()的形式來獲取從服務(wù)器傳過來的數(shù)據(jù),然后從輸入流中讀取相應(yīng)的數(shù)據(jù)存入緩沖區(qū),最后讀取緩沖區(qū)即可以得到所需要的數(shù)據(jù)。把接收到的數(shù)據(jù)存在一個(gè)字符串里面,根據(jù)Android手機(jī)客戶端和PC上位機(jī)的協(xié)議進(jìn)行數(shù)據(jù)的解碼,再把解碼后的數(shù)據(jù)存入到相應(yīng)的字段當(dāng)中,比如經(jīng)度、緯度、速度、駕駛員疲勞狀態(tài)等等。
使用手機(jī)也可以向PC機(jī)發(fā)送數(shù)據(jù)和指令,比如點(diǎn)擊了“車輛監(jiān)控”按鈕時(shí),就需要向PC機(jī)發(fā)送指令,再通過PC機(jī)來控制車輛,從而達(dá)到手機(jī)監(jiān)控車輛的效果。當(dāng)手機(jī)需要向PC機(jī)發(fā)送數(shù)據(jù)時(shí),建立Socket連接之后,是通過輸出流來實(shí)現(xiàn)的,先定義好所要發(fā)送的數(shù)據(jù),再用outputStream. write()語句來將數(shù)據(jù)發(fā)送到Socket服務(wù)器。
由于Socket在連接通信的時(shí)候有可能會(huì)出現(xiàn)異常,所以系統(tǒng)要求加入用來捕捉和處理異常的try-catch語句。程序運(yùn)行正常時(shí),執(zhí)行try{}里面的代碼;當(dāng)出現(xiàn)異常時(shí),執(zhí)行catch里面的語句捕捉和處理異常。Android中Socket通信的部分代碼如下。
try{
Socket Socket = new Socket(\"125.21 6.144.177\",8091); //實(shí)例化Socket
InputStream indata = Socket. getInputStream(); //獲得從服務(wù)器傳過來的數(shù)據(jù)
byte[] buffer = new byte[indata. available()]; //緩沖區(qū)
i n d a t a . r e a d ( b u f f e r ) ;//讀取緩沖區(qū)
String msg = new String(buffer);//轉(zhuǎn)換字符串
System.out.println(msg); //將得到的數(shù)據(jù)進(jìn)行輸出
String[] arr= msg.split(\",\"); //以“,”分割收到的數(shù)據(jù),存入arr[]數(shù)組當(dāng)中
OutputStream outputStream = Socket.getOutputStream(); //獲得輸出流,向服務(wù)器發(fā)送數(shù)據(jù)
byte[] buffer2 = new byte[1111] ;//定義要發(fā)送的數(shù)據(jù)
outputStream.write(buffer2, 0, 6);//開始發(fā)送數(shù)據(jù)
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace(); }
2.2 Android中電子地圖的加載與糾偏
近幾年隨著Android操作系統(tǒng)的興起,越來越多的地圖供應(yīng)商都提供了Android地圖的SDK(軟件開發(fā)包),在Android中開發(fā)地圖加載的流程如下[5]:
Android程序在開發(fā)地圖時(shí),需要在“AndroidManifest.xml”列表中添加多個(gè)應(yīng)用權(quán)限,保證電子地圖能夠正確加載。
然后進(jìn)行初始化設(shè)置,在“SetupMap”函數(shù)中,需要設(shè)置地圖視圖、設(shè)置縮放尺度、將指定坐標(biāo)設(shè)置為地圖中點(diǎn)。
“MapView”類的“setTraffic”方法可以設(shè)置顯示地圖視圖的模式,地圖視圖的模式有衛(wèi)星圖map.setSatellite(true)、一般地圖map.setTraffic(true)、街道圖map. setStreetView。“MapController”類的“setZoom”方法可以控制地圖的縮放尺度。由全球地圖(1)到街道地圖(21),數(shù)值越大地圖細(xì)節(jié)越詳細(xì)。
Android通過“Geopoint”類來定義坐標(biāo),“Geopoint”接受的兩個(gè)參數(shù)分別是“緯度”、“經(jīng)度”值,需要以整數(shù)來表示。“Geopoint”接受的緯度和經(jīng)度手機(jī)通過Socket從上位機(jī)獲取,然后通過實(shí)例化GeoPoint ()對象,在GeoPoint ()輸入緯度和經(jīng)度即可以實(shí)現(xiàn)地圖的加載[6]。
G e o P o i n t p o i n t = n e w GeoPoint((int)(weidu),(int)(jingdu));
無論是Google地圖還是百度地圖,GPS坐標(biāo)直接輸入加載處理的位置是有偏差的,論文使用百度地圖提供的在線API坐標(biāo)轉(zhuǎn)換接口來實(shí)現(xiàn)糾偏,其語句為
G e o P o i n t p o i n t 2= C o o r d i n a t e C o n v e r t . bundleDecode(CoordinateConvert .
fromWgs84ToBaidu(point));進(jìn)行轉(zhuǎn)換之后可以很好的解決坐標(biāo)偏移的問題,測試結(jié)果表明定位誤差在5米以內(nèi)。
為了在地圖上標(biāo)示車輛所在的位置,需要添加一個(gè)定位圖標(biāo)。在Android電子地圖中屬于覆蓋物,所有的覆蓋物都繼承“Overlay”類,本次設(shè)計(jì)自定義一個(gè)CustomItemizedOverlay子類,繼承ItemizedOverlay類,用來實(shí)現(xiàn)標(biāo)注定位圖標(biāo)和定位文字的功能。
3 系統(tǒng)的測試與結(jié)論
在設(shè)計(jì)好監(jiān)控中心和手機(jī)客戶端之后,配合硬件進(jìn)行測試,監(jiān)控中心要具備公網(wǎng)IP,圖4和圖5為監(jiān)控中心的部分界面展示,圖6為Android手機(jī)客戶端界面。
從以上測試結(jié)果可知,本次車聯(lián)網(wǎng)系統(tǒng)的設(shè)計(jì)達(dá)到了預(yù)期目標(biāo),系統(tǒng)總體運(yùn)行流暢,上位機(jī)監(jiān)控中心和Android手機(jī)能夠正確顯示車輛的基本信息、精確顯示車輛的位置、對車輛進(jìn)行監(jiān)控和控制、警示駕駛員是否疲勞等,便于車輛的管理、監(jiān)控、調(diào)度、遠(yuǎn)程診斷等,為我國的智能交通行業(yè)的發(fā)展提供有力的參考。