夏 江 常海軍
[摘要]提出一種在Windce5.0下用EVC和Max mobile結(jié)合GPS全球定位系統(tǒng)定位信息加語音的錄制和回放的技術(shù),實現(xiàn)電子地圖作業(yè)過程中,POI采集和更新程序的實現(xiàn)方法。
[關(guān)鍵詞]MapX- MobileEVC NEMA0183語音 POI
中圖分類號:TP2文獻(xiàn)標(biāo)識碼:A文章編號:1671-7597(2009)0710076-03
電子地圖應(yīng)用的飛速發(fā)展已逐漸在地圖行業(yè)中占有越來越大的比重、同時城市范圍也在不斷的擴(kuò)大,新修的道路和各種設(shè)施比比皆是,電子地圖的更新問題已逐漸成了電子地圖應(yīng)用的一種難言之痛,GPS導(dǎo)航成為了一種普遍采用的導(dǎo)航定位技術(shù),并在精度、實時性、全天候等方面取得了長足進(jìn)步。本文就針對利用前比較普及的GPS系統(tǒng),實現(xiàn)電子地圖中POI更新的一種方法。
一、MapInfo MapX Mobile簡介
MapX Mobile是一個可以用在Pocket PC的MapX平臺,用MapX Mobile
建立的軟件可以單獨在設(shè)備上運行,并能夠和Pocket PC的Windows CE操作系統(tǒng)兼容,不需要無線連接。
二、定位信息的接收
通常GPS定位信息接收系統(tǒng)主要由GPS接收天線、變頻器、信號通道、微處理器、存儲器以及電源等部分組成。由于GPS定位信息內(nèi)容較少,因此多用RS-232串口將定位信息(NEMA0183語句)從GPS接收機傳送到PDA中進(jìn)行信息提取處理。從串口讀取數(shù)據(jù)有多種方法,在此直接使用 Win32 API函數(shù)對其進(jìn)行編程處理。在Wince5.0下不允許直接對硬件端口進(jìn)行控制操作,所有的端口均被視為“文件”,因此在對串口進(jìn)行偵聽之前需要通過打開文件來打開串口,并對其進(jìn)行相關(guān)參數(shù)配置:
m_nPortNr=portNo;
wsprintf(szPort, L"COM%d:", portNo); //設(shè)置串口名
m_hComm = CreateFile(//打開串口
szPort,
GENERIC_READ | GENERIC_WRITE, //允許讀和寫
0, //獨占方式
NULL,OPEN_EXISTING, //打開而不是創(chuàng)建
0, NULL );
// 設(shè)置串口的超時特性為立即返回。
if (!GetCommState(m_hComm,&m_dcb))
{
return FALSE;
}
m_dcb.BaudRate = baud; // 設(shè)置波特率
m_dcb.ByteSize = databits; // 數(shù)據(jù)位,范圍:4-8
m_dcb.Parity = NOPARITY; // 校驗?zāi)J?/p>
m_dcb.StopBits = stopbits; // 停止位
//設(shè)置串口讀寫時間
GetCommTimeouts (m_hComm, &m_CommTimeouts);
m_CommTimeouts.ReadIntervalTimeout = 1000;
m_CommTimeouts.ReadTotalTimeoutMultiplier = 0;
m_pPortOwner = pPortOwner;
//指定端口監(jiān)測的事件集
SetCommMask (m_hComm, EV_RXCHAR | EV_CTS);
//創(chuàng)建讀串口線程
m_hReadThread = CreateThread(NULL,0,ReadThreadFunc,this,0,&
m_dwRThreadID);
return TRUE;
}
在成功創(chuàng)建讀串口線程后,可采取輪詢串口和事件觸發(fā)兩種方式對數(shù)據(jù)進(jìn)行接收處理,本文在此采取效率比較高的事件觸發(fā)方式進(jìn)行接收處理,通過等待EV_RXCHAR事件的發(fā)生來啟動ReadFile函數(shù)完成對GPS定位信息的接收:
ReadThreadFunc(LPVOID lparam)
{
CCESeries *ceSeries = (CCESeries*)lparam;
DWORD evtMask;
BYTE * readBuf = NULL;//讀取的字節(jié)
DWORD actualReadLen=0;//實際讀取的字節(jié)數(shù)
DWORD willReadLen;
DWORD dwReadErrors;
COMSTAT cmState;
// 清空緩沖,并檢查串口是否打開。
ASSERT(ceSeries->m_hComm !=INVALID_HANDLE_VALUE);
//清空串口
PurgeComm(ceSeries->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR );
SetCommMask (ceSeries->m_hComm, EV_RXCHAR | EV_CTS | EV_DSR );
while (TRUE)
{
if (WaitCommEvent(ceSeries->m_hComm,&evtMask,0))
{
SetCommMask (ceSeries->m_hComm, EV_RXCHAR | EV_CTS | EV_DSR );
//表示串口收到字符
if (evtMask & EV_RXCHAR)
{
ClearCommError(ceSeries->m_hComm,&dwReadErrors,&cmState);
willReadLen = cmState.cbInQue ;
readBuf = new BYTE[willReadLen];
ReadFile(ceSeries->m_hComm, readBuf, willReadLen, &actualReadLen,0);
//如果讀取的數(shù)據(jù)大于0,
if (actualReadLen>0)
{
::SendMessage((ceSeries->m_pPortOwner)->m_hWnd, WM_COMM_RXCHAR,
(WPARAM) readBuf, (LPARAM) ceSeries->m_nPortNr);
}
}
}
return 0;
}
三、提取定位數(shù)據(jù)
GPS接收機處于正常工作狀態(tài)時,GPS導(dǎo)航定位信息通過串口按設(shè)定的時間間隔傳送到PDA中。前面的程序代碼只是從串口接收數(shù)據(jù)以字節(jié)流的方式放置于指定緩存中,必須通過程序?qū)⒆止?jié)流中的相關(guān)信息提取出來,將其格式化為符合程序需要的定位信息數(shù)據(jù)。同其他通訊協(xié)議類似,NMEA 0183信息自有其完善幀結(jié)構(gòu)描述體系。對于本文中其發(fā)送到PDA的幀信息主要由幀頭、幀尾和幀內(nèi)數(shù)據(jù)組成,根據(jù)數(shù)據(jù)幀的不同,幀頭也不相同,主要有:
“$GPRMC” 、“$GPGGA”、“$GPGSA” 以及“$GPGSV”等。這些幀頭標(biāo)識了后續(xù)幀內(nèi)數(shù)據(jù)的組成結(jié)構(gòu),各幀均以回車符和換行符標(biāo)識一幀的結(jié)束。
對于通常的情況,定位數(shù)據(jù)如經(jīng)緯度、速度、時間、等均可以從“$GPRMC”幀中獲取得到,而關(guān)于定位時間、緯度、經(jīng)度、高度、定位所用的衛(wèi)星數(shù)、DOP值、差分狀態(tài)和校正時段等相關(guān)信息可從“$GPGGA”幀中獲取得,下面這兩種幀結(jié)構(gòu)的相關(guān)描述:
$GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>*hh
<1>UTC時間,hhmmss(時分秒)格式
<2>定位狀態(tài),A=有效定位,V=無效定位
<3>緯度ddmm.mmmm(度分)格式(前面的0也將被傳輸)
<4>緯度半球N(北半球)或S(南半球)
<5>經(jīng)度dddmm.mmmm(度分)格式(前面的0也將被傳輸)
<6>經(jīng)度半球E(東經(jīng))或W(西經(jīng))
<7>地面速率(000.0~999.9節(jié),前面的0也將被傳輸)
<8>地面航向(000.0~359.9度,以真北為參考基準(zhǔn),前面的0也將被傳輸)
<9>UTC日期,ddmmyy(日月年)格式
<10> 磁偏角(000.0~180.0度,前面的0也將被傳輸)
<11> 磁偏角方向,E(東)或W(西)
<12> 模式指示
$GPGGA,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,M,<10>,M,<11>,<12>*xx
<1>UTC時間,格式為hhmmss.sss
<2>緯度,格式為ddmm.mmmm(第一位是零也將傳送)
<3>緯度半球,N或S(北緯或南緯)
<4>經(jīng)度,格式為dddmm.mmmm(第一位零也將傳送)
<5>經(jīng)度半球,E或W(東經(jīng)或西經(jīng))
<6>定位質(zhì)量指示,0=定位無效,1=定位有效
<7>使用衛(wèi)星數(shù)量,從00到12(第一個零也將傳送)
<8>水平精確度,0.5到99.9
<9>天線離海平面的高度,-9999.9到9999.9米
<10> 大地水準(zhǔn)面高度,-9999.9到9999.9米
<11> 差分GPS數(shù)據(jù)期限(RTCM SC-104),最后設(shè)立RTCM傳送的秒數(shù)量
<12> 差分參考基站標(biāo)號,從0000到1023(首位0也將傳送)
M 指單位米
至于其他幾種幀格式,除了特殊用途外,平時并不常用,雖然接收機也在源源不斷地向主機發(fā)送各種數(shù)據(jù)幀,但在處理時一般先通過對幀頭的判斷而只對"$GPRMC"和$GPGGA幀進(jìn)行數(shù)據(jù)處理。如果情況特殊,需要從其他幀獲取數(shù)據(jù),處理方法與之也是完全類似的。由于幀內(nèi)各數(shù)據(jù)段由逗號分割,因此在處理緩存數(shù)據(jù)時一般是通過搜尋ASCII碼"$"來判斷是否是幀頭,在對幀頭的類別進(jìn)行識別后再通過對所經(jīng)歷逗號個數(shù)的計數(shù)來判斷出當(dāng)前正在處理的是哪一種定位導(dǎo)航參數(shù),并做出相應(yīng)的處理。下面就是對緩存數(shù)據(jù)中的"$GPRMC"和$GPGGA進(jìn)行解幀處理的主要代碼:
$GPRMC:
class CRMCResponse
{
NMEA_TIMEm_Time; // UTC時間
NMEA_DATEm_Date; // UTC日期
BOOL m_IsDataValid;// 定位狀態(tài)
NMEA_LATITUDEm_Latitude; // 緯度
NMEA_LONGITUDE m_Longitude;// 經(jīng)度
double m_Bearing;// 地面航向
//提取出相應(yīng)的數(shù)據(jù)項
BOOL Parse(const CNmeaSentence& sentence);
};
BOOL CRMCResponse:: Parse(const CNmeaSentence& sentence)
{
// 校驗接收到GPS數(shù)據(jù)是否有效,無效則返回
NMEA_BOOLEAN check = sentence.IsChecksumBad(12);
m_Time = sentence.Time(1);
m_Date = sentence.Date(9);
m_Latitude = sentence.Latitude(3, 4);
m_Longitude= sentence.Longitude(5, 6);
return TRUE;
}
$GPGGA:
class CGGAResponse
{
int m_GPSQuality; //GPS信號質(zhì)量
int m_nSatellites;//使用衛(wèi)星數(shù)量
//提取出相應(yīng)的數(shù)據(jù)項
BOOL Parse(const CNmeaSentence& sentence);
};
BOOL CGGAResponse::Parse(const CNmeaSentence& sentence)
{
// 校驗接收到GPS數(shù)據(jù)是否有效,無效則返回
if (sentence.IsChecksumBad(15) == True)
{
return FALSE;
}
m_GPSQuality= sentence.Integer(6);
m_nSatellites = sentence.Integer(7);
return TRUE;
}
現(xiàn)在已將所需信息提取了出來,主要有經(jīng)緯度、地面速率、地面航向、天線離海平面的高度、使用衛(wèi)星數(shù)量、是否差分、時間、日期等分別提取到了相應(yīng)變量中,本程序把經(jīng)緯度作為坐標(biāo)信息以點的形式保存在實際的程序數(shù)據(jù)中,而其它相關(guān)變量則作為相應(yīng)點的屬性進(jìn)行保存。應(yīng)用中往往要根據(jù)需要對其做進(jìn)一步的運算處理,而且GPS使用的WGS-84坐標(biāo)系也與我國采用的坐標(biāo)系不同,有時也要對此加以變換。
四、語音的錄制和回放部分的實現(xiàn)
POI采集和更新涉及到的內(nèi)容較多,這就對采集到的信息描述提出較高的要求,在保證地理空間位置相對準(zhǔn)確的情況下,也要保證采集到的相關(guān)信息的準(zhǔn)確性,比較通用的一些做法是同時采取多種手段來滿足要求,主要有下幾種方式:
現(xiàn)場記錄紙的方式:詳細(xì)記錄每一個信息點相關(guān)信息,回到內(nèi)業(yè)把相關(guān)信息整理出來,這種做法效率較低,本程序不采取這種方法作為輔助手段。
直接錄入程序方式:本文采取的方式是在現(xiàn)場直接把相關(guān)信息的描述寫入程序中,這種做法效率較高,但同時也增加錯誤的幾率,這就需要采取一種輔助手段來幫助修正錯誤,常用的有現(xiàn)場錄音和拍照的方式,本文主要介紹錄音程序的程序?qū)崿F(xiàn),下面是語音文件讀寫主要程序代碼。
class CWaveFile
{
public:
/* 文件內(nèi)部定位 */
unsigned int wave_getpos(wave_file *wf);
char wave_setpos(wave_file *wf, unsigned int pos);
//保存和釋放語音文件占用的內(nèi)存
void wave_free(wave_file *wf);
char wave_save(wave_file *wf);
//保存語音文件
DWORD m_dwFlags;
long Write(char* pData, long nLength);
//打開語音文件
BOOL Open(LPCTSTR szFileName,DWORD dwFlags);
void Close();
//讀取語音數(shù)據(jù)
long Read(char* pData, long nLength);
long GetLength() {return m_nLength;}
protected:
FILE* m_pFile; //文件指針
long m_nLength;//讀取或?qū)懭胛募臄?shù)據(jù)段長度
};
通過以上程序代碼,可以作為輔助手段的語音文件可以非常方便地進(jìn)行讀寫,在進(jìn)行內(nèi)業(yè)數(shù)據(jù)整理的時候,利用采集現(xiàn)場記錄數(shù)據(jù)和相應(yīng)錄音可以進(jìn)一步提高信息描述的準(zhǔn)確性。
上面是本文中提到的程序的主要實現(xiàn)模塊,具體的環(huán)境有不同的應(yīng)用要求,實現(xiàn)細(xì)節(jié)也可能不同,但此種做業(yè)方式對電子地圖數(shù)據(jù)的采集和更新來說,經(jīng)過實際工作的檢驗,還是比較實用的。
五、小結(jié)
本文結(jié)合主要的相關(guān)程序代碼對電子地圖數(shù)據(jù)的采集和更新進(jìn)行了模塊說明,包括NMEA 0183格式說明、串口的程序設(shè)計、語音模塊作了簡要的講述。通過本文的設(shè)計方法可提高電子地圖數(shù)據(jù)的采集和更新效率和數(shù)據(jù)質(zhì)量。本文程序在Windows xp下,由EVC++ 4.0編譯通過。
參考文獻(xiàn):
[1]李勝樂,MapInfo地理信息系統(tǒng)二次開發(fā)實例,電子工業(yè)出版社.
[2]汪兵、李存斌、陳鵬等,EVC高級編程及其應(yīng)用開發(fā)(EMBEDDED VISUAL C++嵌入式編程),中國水利水電出版社.
[3]譚思亮、鄒超群,Visual C++串口通信工程開發(fā)實例導(dǎo)航,人民郵電出版社.
[4]MapX 開發(fā)人員指南,MapInfo Corporation Troy,NY.
[5]Programming Microsoft Windows CE.NET,Third Edition,Douglas Boling Microsoft Press.
[6]NMEA-0183 Protocol Description, Mihai, www.remember.ro.
作者簡介:
夏江,女,53歲,工程師,河北省地礦局測繪院制圖分院副院長、技術(shù)負(fù)責(zé),從事測繪工作34年;常海軍,河北省地礦局測繪院制圖分院,工程師。