摘 要:为了提高船舶试航测试系统定位数据的精确性与可靠性,同时适应现代试航测试系统的整体性能要求,开发了一种基于GPS的船舶试航数据提取与存储系统。建立了总体架构,提出了基于多线程的GPS串口通信和SQL数据存储的数据处理改进技术,开发了软件系统。通过测试,证明新技术在提高试航定位数据性能方面效果显著,同时精度符合实际需求。
关键词:全球定位系统;串口通信;多线程;微软基础类编程;应用程序编程接口
船舶试航是新船出厂前的一个重要测试过程,其目的在于测试船舶的航行性能,并对船舶设计方的设计做出评价,同时这些船舶实际航行的测试资料,可以为设计方设计新船舶时提供参考。
船舶试航大部分采用GPS获取船舶的定位数据,由计程仪、罗经等相关设备记录参数,然后通过计算和绘制航迹曲线获得船舶性能。传统试航作业中,一般通过手工和计算机辅助设备获得数据,人工干预度高,难以有效获得精确度高的数据,已无法满足现代试航系统的数据性能要求。
目前船厂所用的船舶试航系统软件大多工作在DOS界面上,存在稳定性差、数据安全性弱、移植性差以及人机交互不够友好等问题。为克服DOS系统带来的不便,2001年华南理工大学开发了一套基于VB开发的GPS船舶测试系统,整个系统虽然结构较为清晰,但由于VB本身特点,对数据处理性能以及系统稳定性有着一定的局限性。2006年,上海海事大学发表了一篇题为《基于GPS的船舶航行试验系统研究》的论文,在VC++平台上,应用GPS技术、计算机处理技术设计了一套完整的试航测试系统,增强了系统稳定性,但仍然存在数据接收和不能进行同步处理的问题。
为改善已有试航数据系统功能,有效提高数据稳定性与可靠性,本文在VC++平台上,通过多线程技术以及数据提取方式的优化,提出一个新的GPS船舶试航数据处理系统。系统的主要优势在于实时有效地接收处理GPS定位数据,提高数据精度,并结合SQL数据库技术安全存储。
1 系统组成
GPS船舶试航数据提取与存储系统是GPS船舶试航系统的数据接收、处理、存储部分,主要由两大部分组成,如图1所示。其中,GPS串口通信部分主要是对GPS接收机中接收到的船舶的卫星定位数据进行提取处理;数据库存储部分将提取处理后的有用数据按照一定的格式存储入数据库以供后期使用。
2 GPS串口通信
GPS接收机通过串口与PC机相连,将GPS定位数据传输到PC机,作为整个系统的数据源。由于本系统工作在现场,需要满足实时稳定的通信需求,并保证接收到的GPS数据的有效性与完整性。为此,本文采用基于多线程的串口通信技术,能做到在接收定位数据的同时,对其进行提取处理。
2.1 串口通信编程
GPS串口通信的开发模式通常有Windows API、串口通信组件MSComm及第三方串口通信类。
其中,MSComm控件虽然编程简单,但是由于进行了大量封装,其编程的灵活性、稳定性、可控性较差;第三方串口通信类是个介于WinAPI与MScomm控件之间的方式,有一定的封装性,但相对灵活可控,唯一的缺陷在于移植性要逊于API函数。新船试航系统需要一个能满足较高精度,工作在现场,并且可以根据需要适应各种设备的数据提取与存储系统。同时API函数法作为与计算机底层设备联系最为紧密的一种实现方法,与MSComm控件和第三方通信类相比,应用于多线程系统时有更好的稳定性。因而API函数法能更好满足试航系统需求,故本文采用API函数法来实现串口通信。
2.2 多线程编程
Windows多线程编程可以使用两种方法:直接使用Win32 API或MFC线程技术。其中MFC编程较为简便,更方便实现界面线程。在MFC线程技术中,线程分为用户界面线程和工作者线程。用户界面线程有自己的消息队列和消息循环来处理界面消息,用来与用户进行交互;工作者线程没有消息循环,一般用来完成后台工作。
结合实际需要以及编程的难易程度,本文选择MFC线程技术实现多线程。
2.3 多线程串口通信的实现
串口通信部分分为数据处理与数据接收两大部分。数据处理主线程CDataFlow,用于对接收到的数据提取处理;数据接收工作线程CThreadCom,用于监视串口状态以及对GPS数据的接收。其中用WaitCommEvent函数对串口进行监视,一旦有数据到达,即可读取进缓存区,从而增加了数据的实时性。数据接收与数据处理两个线程的流程如图2所示。
从图中可以看到,接收到的数据将从缓冲区中读出并存储在缓存数据文件中,这样既可以不必考虑数据处理速度对于数据接收所造成的影响,也不会造成丢失数据帧,在数据实时接收的同时,保证了数据接收的完整性。下面分别说明数据处理主线程与数据接收线程的具体实现。
(1)GPS数据格式
在说明如何实现数据接收之前,本文先讨论一下GPS接收机的数据接收格式。GPS数据遵循NMEA0183协议,该协议主要用来传输GPS定位信息,卫星信息、经纬度信息、速度、时间等信息,输出标准ASCII码形式的数据信息,协议包括GPGGA、GPGSA、GPRMC、GPGLL等多种数据格式,数据格式都以“$”开头,到*表示校验码开始,hh表示语句校验码,本文需要提取GPGGA与GPRMC中的信息。
(2)数据接收
针对实时接收数据的要求,本文使用WaitCommEvent()对串口数据进行接收。在API函数中,WaitCommEvent()、WaitForMultipleObject()和GetOverlappedResult()等函数均可以检测到串口是否有数据。其中waitforMultipleobjects()作用为等待多个被监测内核对象的结果,getoverlappedresult()为返回最后重叠操作结果。相比之下,waitcommevent()是一个特指的通信设备等待一个事件发生,并监控与该设备句柄相关联的一系列事件。用该函数接收数据时,一旦数据到达串口,系统将会马上检测到,并做好接收的准备,其关键实现代码如下:
While(m_hcom!=INVALID_HANDLE_VALUE)
{dwEvent=0
WaitCommEvent(m_hCom,&dwEvent,Null);
//检查串口事件
If((dwEvent&EV_RXCHAR)==EV_RXCHAR)
//如果发现有串口数据接收事件,接收数据
{do//循环接收串口数据
{if(nLength=ReceiveData((LPSTR)rBuf,
MAX_COM_IN_LENGTH))//
{if(dwEVENT&~EV_RXCHAR)
//如果串口数据中有字符接收事件,
//则将事件传送CDataFlow进行处理
{if(m_pWndData)
{m_pWndData->SendMessage(m_dwMsgToData,dwEvent,0);}}}
If(nLength)//接收到数据传给CDataFlow处理
{if(m_pWndData)
{m_pWndData->SengMessage(m_dwMsgToData,(DWORD)rBuf,nLength);}}
}while(nLength>0);}sleep(1);}sleep(1);}
(3)GPS数据处理
作为串口通信的主线程,数据处理主要功能是在缓存区中将GPGGA与GPRMC数据取出,通过数据提取函数DealFlow提取数据包,进行校验处理后,发送消息给解码函数OnDecodeMsg进行协议解析:先将有用NMEA数据提取,分割成数组,随后对数组进行操作,得到需要的数据信息。这种先检验后分割再提取的处理方法有助于提高数据质量。流程图如图2所示,下面以GPGGA解码为例,给出关键代码与说明:
for(itemCount=1;itemCount<total;itemCount++)
{iLen=0//设置每项从数据的第一个字符开始处理
CString*item=m_dataArray.GetAt(itemCount);//
Switch(itemCount)//
{case1:itemLen=2;
CGPSPublic::ConverToInt((int&)pack-
>GPS_NMEA_GPGGA.body.time.hour,
item->Mid(iLen,itemLen));//
CGPSPublic::ConverToInt((int&)pack->
GPS_NMEA_GPGGA.body.time.minute,
item->Mid(iLen,itemLen));//
CGPSPublic::ConverToInt((int&)pack->
GPS_NMEA_GPGGA.body.time.second,
item->Mid(iLen,itemLen));//break;
case2:CGPSPublic::ConverToLatitudeHavePoint(
(double&)pack->GPS_NMEA_GPGGA.body.latitude.lati
tude,*item);//break;
case3:itemLen=1;
CGPSPublic::ConverToChar((char&)pack->
GPS_NMEA_GPGGA.bady.latitudetype,
*item->Mid(iLen,itemLen),itemLen);break;
……
值得一提的是,在数据提取与校验实现算法中,对字符串操作的函数必不可少,本文主要通过使用以下几个主要函数对字符串操作:
(1)Find()函数
该函数用于查找指定目标第一次出现在字符串中位置,如果不存在即返回值-1。Find函数在数据截取算法中主要用于查找回车符,以及NMEA-0183协议中的逗号,返回的位置参数对后面Delete函数的应用起到重要的作用。
(2)Delete()函数
该函数用于删除字符串中无用的内容,Delete()函数包括2个基本参数,即起始位置和终点位置,函数将删除之间的内容。
(3)Compare()函数
该函数用于比较字符串与目标字符串之间区别,可以有效地在包含大量信息的字符串中筛选出有用信息。如果字符串与目标字符串相同,则返回值为0,不相同则返回值不为0。
3 数据库存储
船舶试航定位信息数据库作为后台数据库,不仅要提供一种可靠的数据存储,作为定位数据信息的容器,同时还需有效地管理其中数据信息,并提供高效的数据访问和恢复机制。下面将通过数据表的设计与ODBC数据库互联两个部分来说明如何实现高效可靠的数据存储。
(1)SQL Server数据库配置与数据表设计
在安装和完成SQL Server本地配置之后,需要新建一个数据库,并添加一张表用于储存数据。本系统需要储存的参数是经度、纬度、速率、航向这4个数据,因此在数据库的列设置中,需要添加这4个名称,并且设置字符类型。由于速率和航向在位移很小时,不会显示数据,为了避免之后编译中出错,应允许数据为NULL值。由于GPS接收机接收到的经纬度坐标最大长度不超过10位,因而字符类型设置为nchar(10)。
(2)ODBC数据库互联
开放数据库互联是微软公司开放服务结构中有关数据库的一个组成部分,它建立了一组规范,并提供了一组对数据库访问的标准API。这些API利用SQL来完成其大部分任务。ODBC本身也提供了对SQL语言的支持,用户可以直接将SQL语句送给ODBC。
定位信息数据库需要完成的主要任务是:数据动态存储、数据表操作和数据调用,其中用到的VC++中MFC基类库定义了3个数据库类,CDatabase(数据库类):对象提供数据源连接、CRecordSet(记录集类):对象提供数据源动态行集方式的记录集以及CRecordView(可视记录集类):对象以控制的形式显示数据库记录。
在VS2010中关联数据库需要添加MFCODBC使用者这个类,在设置完成类MFCODBC使用者之后,程序会自动添加两个文件,分别是Table_1.h和Table_1.cpp(Table_1是数据库中设置的表的名称),并生成一个CTable_1的类,通过这个类,可以定义数据库指针,即:Ctable_1 m_pSet。在VC++中,通过这个指针可以实现对数据库的数据添加、删除、查找等功能,也可以通过“.”运算代码进行定位和赋值。在添加新记录后,需要使用Updata()函数将缓存中保存的数据写入数据库中,从而完成数据库的储存。同样,数据读取功能也可以通过对指针的操作完成。图3为数据存入情况。
本文在VC++6.0环境下,结合SQL Server技术,对GPS定位数据进行接收与提取,并存入数据库中,以供GPS船舶试航作为基础数据。其中,串口通信部分不仅利用了多线程技术,将数据接收与数据处理分开,有效地提高了数据的处理能力;同时在数据处理时,还通过对数据包进行预处理,剔除接收中可能产生的掉帧数据,继而将NMEA语句分割,存入数组,并对数组进行相应解码,实现了在提高效率的同时减少出错的几率。最后将解析后的数据自动存入数据库,供GPS船舶试航系统作为基础数据。
作为GPS新船舶试航系统的数据源,本系统已通过测试,其精度符合船厂要求,操作界面友好,现场运行效果良好。
参考文献
[1] 徐志京,许开宇,胡文烨.基于GPS的船舶航行试验系统研究[C].大连:中国航海学会通信导航专业委员会2006年学术年会论文集,大连海事大学出版社,2006.
[2] 李莉.GPS接收机串口通信的MSComm和API实现[J].中国新通信,2010(6):81-84.
[3] 陈凯,邓明,张启升,等.Windows CE下多线程串口通信[J].微计算机信息,2007,23(10-2).
[4] 刘书智.Visual C++串口通信与工程应用实践[M].北京:中国铁道出版社,2011.
[5] 刘夏.基于VB的GPS定位算法与软件实现[J].计算机与数字工程,2013(2):208-211.
[6] 刘岩,汪剑云,吴北平,等.基于VB.NET的GPs接收机串口通信的实现[J].地理空间信息,2012,10(2):47-49.
[7] 李冰,曾连荪.GPS定位信息提取及应用[J].电子设计工程,2012,20(12):72-74.
[8] 沈振汉,黄华灿.PC机与GPS接收机的通讯程序设计与实现[J].华侨大学学报(自然科学版),2011.32(1):118-120.
[9] 王靖,纪元法,孙希延,等.高动态GPS信号模拟器中串口通信的实现[J].桂林电子科技大学学报,2010,30(1):30-32.
[10] 阳世荣.基于Keil与VSPD软件仿真的串口通信调试技术[J].舰船电子工程,2010,30(1):30-32.