一、定位数据坐标系
目前国内主要有以下三种坐标系:
WGS84:为一种大地坐标系,也是目前广泛使用的GPS全球卫星定位系统使用的坐标系。
GCJ02:又称火星坐标系,是由中国国家测绘局制订的地理信息系统的坐标系统。由WGS84坐标系经加密后的坐标系。
buff:$GPGSA,A,2,05,,,,,,,,,,,,4.7,4.6,1.0*36buff:$GPGSV,3,1,12,05,11,108,13,24,67,144,26,29,03,206,29,10,15,306,*73buff:$GPGSV,3,2,12,23,42,320,,32,00,250,,39,,,37,40,,,34*76buff:$GPGSV,3,3,12,41,,,44,43,,,38,45,,,38,49,,,34*73buff:$GPGGA,044843.00,3150.789943,N,11717.308136,E,1,01,4.3,27.9,M,-2.0,M,,*47buff:$GPVTG,50.5,T,54.9,M,1.4,N,2.7,K,A*2Bbuff:$GPRMC,044843.00,A,3150.789943,N,11717.308136,E,1.4,50.5,031120,4.4,W,A*1D============================================================ Global Navigation Satellite System== Author:mate== Email:mate20201321@aliyun.com== Platform:A3352+EC20 R2.1============================================================ GPS state bit : A [A:有效状态 V:无效状态]== GPS mode bit : A [A:自主定位 D:差分定位]== Date : 2020-11-03== Time : 12:48:43== 纬度 : 北纬:31度50分47秒== 经度 : 东经:117度17分18秒== 速度 : 1.400 kn(节)============================================================buff:$GPGSA,A,2,05,,,,,,,,,,,,4.4,4.3,1.0*30buff:buff:$GPGSV,3,1,12,05,11,108,13,24,67,144,26,29,03,206,29,10,15,306,*73buff:buff:$GPGSV,3,2,12,23,42,320,,32,00,250,,39,,,37,40,,,34*76buff:buff:$GPGSV,3,3,12,41,,,44,43,,,38,45,,,38,49,,,34*73buff:buff:$GPGGA,044844.00,3150.790220,N,11717.308554,E,1,01,500.0,27.9,M,-2.0,M,,*44buff:buff:$GPVTG,50.1,T,54.5,M,1.4,N,2.7,K,A*23buff:buff:$GPRMC,044844.00,A,3150.790220,N,11717.308554,E,1.4,50.1,031120,4.4,W,A*18============================================================ Global Navigation Satellite System== Author:mate== Email:mate20201321@aliyun.com== Platform:A3352+EC20 R2.1============================================================ GPS state bit : A [A:有效状态 V:无效状态]== GPS mode bit : A [A:自主定位 D:差分定位]== Date : 2020-11-03== Time : 12:48:44== 纬度 : 北纬:31度50分47秒== 经度 : 东经:117度17分18秒== 速度 : 1.400 kn(节)============================================================
二、GPS模组数据处理
GPS上电后,每隔一定的时间就会返回一定格式的数据,数据格式为:
$信息类型,x,x,x,x,x,x,x,x,x,x,x,x,x
每行开头的字符都是‘$’,接着是信息类型,后面是数据,以逗号分隔开。一行完整的数据如下:
$GNGGA,093100.000,3151.10397,N,11707.63497,E,1,11,2.6,214.7,M,-5.0,M,,*50$GNGLL,3151.10397,N,11707.63497,E,093100.000,A,A*49$GNGSA,A,3,02,05,12,20,25,,,,,,,,3.9,2.6,2.9,1*35$GNGSA,A,3,10,13,28,33,38,41,,,,,,,3.9,2.6,2.9,4*36$GPGSV,3,1,10,02,60,349,39,05,38,247,41,06,49,057,27,12,30,263,31,0*65$GPGSV,3,2,10,13,,,24,17,17,143,,19,39,141,29,20,21,248,39,0*5F$GPGSV,3,3,10,25,15,299,44,195,,,26,0*6C$BDGSV,3,1,09,05,,,35,10,37,218,28,13,52,318,41,27,,,36,0*72$BDGSV,3,2,09,28,48,323,46,33,73,210,33,38,61,342,42,40,,,37,0*42$BDGSV,3,3,09,41,20,218,40,0*45$GNRMC,093100.000,A,3151.10397,N,11707.63497,E,0.00,0.00,280521,,,A,V*08$GNVTG,0.00,T,,M,0.00,N,0.00,K,A*23$GNZDA,093100.000,28,05,2021,00,00*4D$GPTXT,01,01,01,ANTENNA OK*35
1、NMEA-0183协议
NMEA-0183协议是为了在不同的GPS(全球定位系统)导航设备中建立统一的BTCM(海事无线电技术委员会)标准,由美国国家海洋电子协会(NMEA-The National Marine Electronics Associa-tion)制定的一套通讯协议。GPS接收机根据NMEA-0183协议的标准规范,将位置、速度等信息通过串口传送到PC机、PDA等设备。
NMEA-0183协议是GPS接收机应当遵守的标准协议,也是目前GPS接收机上使用最广泛的协议,大多数常见的GPS接收机、GPS数据处理软件、导航 软件都遵守或者至少兼容这个协议。
NMEA-0183协议定义的语句非常多,但是常用的或者说兼容性最广的语句只有$GPGGA、$GPGSA、$GPGSV、$GPRMC、$GPVTG、$GPGLL等。
(1) GPS DOP and Active Satellites(GSA)当前卫星信息
$GPGSA,<1>,<2>,<3>,<3>,,,,,<3>,<3>,<3>,<4>,<5>,<6>,<7><1>模式 :M =手动, A =自动。<2>定位型式 1 =未定位, 2 =二维定位, 3 =三维定位。<3>PRN 数字:01至 32表天空使用中的卫星编号,最多可接收12颗卫星信息。<4> PDOP位置精度因子(0.5-99.9)<5> HDOP水平精度因子(0.5-99.9)<6> VDOP垂直精度因子(0.5-99.9)<7> Checksum.(检查位).
这里整条语句是一个文本行,行中以逗号“,”隔开各个字段,每个字段的大小(长度)不一,这里的示例只是一种可能,并不能认为字段的大小就如上述例句一样。
(2)GPS Satellites in View(GSV)可见卫星信息
$GPGSV, <1>,<2>,<3>,<4>,<5>,<6>,<7>,?<4>,<5>,<6>,<7>,<8><1> GSV语句的总数<2> 本句GSV的编号<3> 可见卫星的总数,00至12。<4> 卫星编号, 01至32。<5>卫星仰角, 00至90度。<6>卫星方位角, 000至359度。实际值。<7>讯号噪声比(C/No),00 至99 dB;无表未接收到讯号。<8>Checksum.(检查位).第<4>,<5>,<6>,<7>项个别卫星会重复出现,每行最多有四颗卫星。其余卫星信息会于次一行出现,若未使用,这些字段会空白。
(3)Global Positioning System Fix Data(GGA)GPS定位信息
$GPGGA,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,M,<10>,M,<11>,<12>*hh<1> UTC时间,hhmmss(时分秒)格式<2> 纬度ddmm.mmmm(度分)格式(前面的0也将被传输)<3> 纬度半球N(北半球)或S(南半球)<4> 经度dddmm.mmmm(度分)格式(前面的0也将被传输)<5> 经度半球E(东经)或W(西经)<6> GPS状态:0=未定位,1=非差分定位,2=差分定位,6=正在估算<7> 正在使用解算位置的卫星数量(00-12)(前面的0也将被传输)<8> HDOP水平精度因子(0.5-99.9)<9> 海拔高度(-9999.9-99999.9)<10> 地球椭球面相对大地水准面的高度<11> 差分时间(从最近一次接收到差分信号开始的秒数,如果不是差分定位将为空)<12> 差分站ID号0000~1023(前面的0也将被传输,如果不是差分定位将为空)
hh——校验和(check sum),$与*之间的(不包括这两个字符)所有字符ASCII码的校验和(各字节做异或运算,得到校验和后,再转换16进制格式的ASCII字符。)
(4)Recommended Minimum Specific GPS/TRANSIT Data(RMC)推荐定位信息
$GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>*hh<1> UTC时间,hhmmss(时分秒)格式<2> 定位状态,A=有效定位,V=无效定位<3> 纬度ddmm.mmmm(度分)格式(前面的0也将被传输)<4> 纬度半球N(北半球)或S(南半球)<5> 经度dddmm.mmmm(度分)格式(前面的0也将被传输)<6> 经度半球E(东经)或W(西经)<7> 地面速率(000.0-99.9节,前面的0也将被传输)<8> 地面航向(000.0-359.9度,以真北为参考基准,前面的0也将被传输)<9> UTC日期,ddmmyy(日月年)格式<10> 磁偏角(000.0-180.0度,前面的0也将被传输)<11> 磁偏角方向,E(东)或W(西)<12> 模式指示(仅NMEA0183 3.00版本输出,A=自主定位,D=差分,E=估算,N=数据无效)
hh——校验和(check sum),$与*之间的(不包括这两个字符)所有字符ASCII码的校验和(各字节做异或运算,得到校验和后,再转换16进制格式的ASCII字符。)
(5)Track Made Good and Ground Speed(VTG)地面速度信息
$GPVTG,<1>,T,<2>,M,<3>,N,<4>,K,<5>*hh<1> 以真北为参考基准的地面航向(000-359度,前面的0也将被传输)<2> 以磁北为参考基准的地面航向(000-359度,前面的0也将被传输)<3> 地面速率(000.0-999.9节,前面的0也将被传输)<4> 地面速率(0000.0-1851.8公里/小时,前面的0也将被传输)<5> 模式指示(仅NMEA0183 3.00版本输出,A=自主定位,D=差分,E=估算,N=数据无效)
hh——校验和(check sum),$与*之间的(不包括这两个字符)所有字符ASCII码的校验和(各字节做异或运算,得到校验和后,再转换16进制格式的ASCII字符。)
2、GPS数据获取与解析
(1)根据协议定义GPS数据结构体
typedef unsigned int UINT;/*$GPRMC,语句ID,表明该语句为Recommended Minimum Specific GPS/TRANSIT Data(RMC)*/typedef struct __gprmc__{UINT time_GT; /*<1> UTC时间,hhmmss(时分秒)格式 */char pos_state; /*<2> 定位状态,A=有效定位,V=无效定位 */float latitude; /*<3> 纬度ddmm.mmmm(度分)格式(前面的0也将被传输)) */char NorS; /*<4> 纬度半球N(北半球)或S(南半球) */float longitude; /*<5> 经度dddmm.mmmm(度分)格式(前面的0也将被传输) */char EorW; /*<6> 经度半球E(东经)或W(西经) */float speed; /*<7> 地面速率(000.0~999.9节,前面的0也将被传输) */float direction; /*<8> 地面航向(000.0~359.9度,以真北为参考基准,前面的0也将被传输) */UINT Recdate; /*<9> UTC日期,ddmmyy(日月年)格式 */float declination; /*<10> 磁偏角(000.0~180.0度,前面的0也将被传输) */char dd; /*<11> 磁偏角方向,E(东)或W(西) */char mode; /*<12> 模式指示(仅NMEA0183 3.00版本输出,A=自主定位,D=差分,E=估算,N=数据无效)*/}GPRMC;/*$GPGGA,语句ID,表明该语句为Recommended Minimum Specific GPS/TRANSIT Data(RMC)*/typedef struct __gpgga__{UINT time_GT; /*<1> UTC时间,hhmmss(时分秒)格式 */float latitude; /*<2> 纬度ddmm.mmmm(度分)格式(前面的0也将被传输)) */char NorS; /*<3> 纬度半球N(北半球)或S(南半球) */float longitude; /*<4> 经度dddmm.mmmm(度分)格式(前面的0也将被传输) */char EorW; /*<5> 经度半球E(东经)或W(西经) */unsigned char pos_state; /*<6> 定位状态,1=有效定位,0=无效定位 */unsigned char NumofSat; /*<7> 使用卫星数量,从00到12(第一个零也将传送) */float Lev_accu; /*<8> 水平精确度,0.5到99.9 */float Sea_level; /*<9> 天线离海平面的高度,-9999.9到9999.9米M指单位米 */float Geoid; /*<10> 大地水准面高度,-9999.9到9999.9米M指单位米 */char data_dura; /*<11> 差分GPS数据期限(RTCMSC-104),最后设立RTCM传送的秒数量 */char station_label; /*<12> 差分参考基站标号,从0000到1023(首位0也将传送)*/}GPGGA;
(2)通过串口获取GPS字符串数据
int Get_GPS_Data(int fd_read, unsigned char *SavdBuf, size_t SavdBufSize ){char ReadBuf[GPS_LEN];GPRMC gprmc;memset(&gprmc, 0, sizeof(GPRMC));struct pollfd PollFd;PollFd.fd = fd_read;PollFd.events = POLLIN;if(poll(&PollFd,1,1) && (PollFd.revents & POLLIN) ) //等待数据s{memset(ReadBuf, 0, sizeof(ReadBuf));size_t ReadSize = read(PollFd.fd, ReadBuf, sizeof(ReadBuf));if(ReadSize <0){perror("read error");return -1;}#if IS_DEBUGprintf("ReadBuf:\n");printf("%s",ReadBuf);#endifmemset(&gprmc, 0 , sizeof(gprmc));if( (Analyse_GPRMC_GPS(ReadBuf, ReadSize, &gprmc)== 0 ) && (gprmc.pos_state == 'A') ){GPS_Data_Resolve ( &gprmc , SavdBuf, SavdBufSize );#if IS_DEBUGPrint_GPRMC_GPS(&gprmc);printf("纬度 = %f\n", Bytes2Float ( SavdBuf , sizeof(float)));printf("精度 = %f\n", Bytes2Float ( SavdBuf+sizeof(float)+sizeof(char) , sizeof(float)));#endifreturn 0;}elseprintf("Invalid location!\n");return -1;}elseprintf("NO GPS DATA!\n");return -1;}
(3)解析GPS数据字符串
int Analyse_GPRMC_GPS (char *ReadBuf, size_t ReadSize, GPRMC *gps_data){char *ptr=NULL;if(gps_data==NULL)return -1;if(strlen(ReadBuf)<10)return -1;/* 如果buff字符串中包含字符"$GPRMC"则将$GPRMC的地址赋值给ptr */if((ptr=strstr(ReadBuf,"$GPRMC"))==NULL)return -1;int i=0;for( i=0; i<ReadSize-(ptr-ReadBuf);i++) //查找一行$GPRMC数据的结尾(换行符){if(ptr[i] == '\n') //说明是完整的一组"$GPRMC"数据,否则就丢弃break;}if(i == ReadSize-(ptr-ReadBuf))return -1;/* sscanf函数为从字符串输入,意思是将ptr内存单元的值作为输入分别输入到后面的结构体成员 */sscanf(ptr,"$GPRMC,%d.00,%c,%f,%c,%f,%c,%f,%f,%d,%f,%c,%c*",&(gps_data->time_GT), &(gps_data->pos_state),&(gps_data->latitude),&(gps_data->NorS), &(gps_data->longitude), &(gps_data->EorW),&(gps_data->speed), &(gps_data->direction), &(gps_data->Recdate),&(gps_data->declination), &(gps_data->dd), &(gps_data->mode));return 0;}
(4)GPS数据转为通信协议格式

ssize_t GPS_Data_Resolve (GPRMC *gps_data, unsigned char *ResolvedBuf, size_t ResolvedBufMaxSize ){size_t PackagedDataSize = 0;unsigned char tempbuf[sizeof(float)] = { 0 };//纬度转为字节Float2Bytes ( gps_data->latitude, tempbuf ,sizeof(float));PackagedDataSize = PackingData( 1, ResolvedBuf, ResolvedBufMaxSize, PackagedDataSize ,tempbuf ,sizeof(float) );//保存南北纬字符ResolvedBuf[PackagedDataSize] = gps_data->NorS;PackagedDataSize++;//经度转为字节memset(tempbuf, 0, sizeof(float));Float2Bytes ( gps_data->longitude, tempbuf ,sizeof(float));PackagedDataSize = PackingData( 1, ResolvedBuf, ResolvedBufMaxSize, PackagedDataSize ,tempbuf ,sizeof(float) );//保存东西经字符ResolvedBuf[PackagedDataSize] = gps_data->EorW;PackagedDataSize++;//速度转为字节memset(tempbuf, 0, sizeof(float));Int2Bytes ((long)(gps_data->speed * 10), tempbuf , 2);PackagedDataSize = PackingData( 1, ResolvedBuf, ResolvedBufMaxSize, PackagedDataSize ,tempbuf ,2);return PackagedDataSize;}
(5)显示解析结果
int Print_GPRMC_GPS (GPRMC *gps_data){printf("\n\n");printf("==========================================================\n");printf("== Global Navigation Satellite System \n");printf("== Author : mate \n");printf("== Email : mate20201321@aliyun.com \n");printf("== Platform : A3352+EC20 R2.1 \n");printf("==========================================================\n");printf("== GPS state : %c [A:Available V:Void] \n", gps_data->pos_state);printf("== GPS mode : %c [A:Autonomic D:DGPS] \n", gps_data->mode);printf("== Date : 20%02d-%02d-%02d \n", gps_data->Recdate%100,(gps_data->Recdate%10000)/100,gps_data->Recdate/10000);printf("== Time : %02d:%02d:%02d \n", (gps_data->time_GT/10000+8)%24,(gps_data->time_GT%10000)/100,gps_data->time_GT%100);printf("== latitude : %c %d° %d' %d\" \n", gps_data->NorS, ((int)gps_data->latitude) / 100, (int)(gps_data->latitude - ((int)gps_data->latitude / 100 * 100)), (int)(((gps_data->latitude - ((int)gps_data->latitude / 100 * 100)) - ((int)gps_data->latitude - ((int)gps_data->latitude / 100 * 100))) * 60.0));printf("== longitude : %c %d° %d' %d\" \n", gps_data->EorW, ((int)gps_data->longitude) / 100, (int)(gps_data->longitude - ((int)gps_data->longitude / 100 * 100)), (int)(((gps_data->longitude - ((int)gps_data->longitude / 100 * 100)) - ((int)gps_data->longitude - ((int)gps_data->longitude / 100 * 100))) * 60.0));printf("== velocity : %.3f kn \n", gps_data->speed); //1kn = 0.5144444 m/sprintf("==\n");printf("==========================================================\n");return 0;}
