一、定位数据坐标系

目前国内主要有以下三种坐标系:
WGS84:为一种大地坐标系,也是目前广泛使用的GPS全球卫星定位系统使用的坐标系。
GCJ02:又称火星坐标系,是由中国国家测绘局制订的地理信息系统的坐标系统。由WGS84坐标系经加密后的坐标系。

  1. buff:
  2. $GPGSA,A,2,05,,,,,,,,,,,,4.7,4.6,1.0*36
  3. buff:
  4. $GPGSV,3,1,12,05,11,108,13,24,67,144,26,29,03,206,29,10,15,306,*73
  5. buff:
  6. $GPGSV,3,2,12,23,42,320,,32,00,250,,39,,,37,40,,,34*76
  7. buff:
  8. $GPGSV,3,3,12,41,,,44,43,,,38,45,,,38,49,,,34*73
  9. buff:
  10. $GPGGA,044843.00,3150.789943,N,11717.308136,E,1,01,4.3,27.9,M,-2.0,M,,*47
  11. buff:
  12. $GPVTG,50.5,T,54.9,M,1.4,N,2.7,K,A*2B
  13. buff:
  14. $GPRMC,044843.00,A,3150.789943,N,11717.308136,E,1.4,50.5,031120,4.4,W,A*1D
  15. ==========================================================
  16. == Global Navigation Satellite System
  17. == Authormate
  18. == Emailmate20201321@aliyun.com
  19. == PlatformA3352+EC20 R2.1
  20. ==========================================================
  21. == GPS state bit : A [A:有效状态 V:无效状态]
  22. == GPS mode bit : A [A:自主定位 D:差分定位]
  23. == Date : 2020-11-03
  24. == Time : 12:48:43
  25. == 纬度 : 北纬:315047
  26. == 经度 : 东经:1171718
  27. == 速度 : 1.400 kn(节)
  28. ==
  29. ==========================================================
  30. buff:
  31. $GPGSA,A,2,05,,,,,,,,,,,,4.4,4.3,1.0*30
  32. buff:
  33. buff:
  34. $GPGSV,3,1,12,05,11,108,13,24,67,144,26,29,03,206,29,10,15,306,*73
  35. buff:
  36. buff:
  37. $GPGSV,3,2,12,23,42,320,,32,00,250,,39,,,37,40,,,34*76
  38. buff:
  39. buff:
  40. $GPGSV,3,3,12,41,,,44,43,,,38,45,,,38,49,,,34*73
  41. buff:
  42. buff:
  43. $GPGGA,044844.00,3150.790220,N,11717.308554,E,1,01,500.0,27.9,M,-2.0,M,,*44
  44. buff:
  45. buff:
  46. $GPVTG,50.1,T,54.5,M,1.4,N,2.7,K,A*23
  47. buff:
  48. buff:
  49. $GPRMC,044844.00,A,3150.790220,N,11717.308554,E,1.4,50.1,031120,4.4,W,A*18
  50. ==========================================================
  51. == Global Navigation Satellite System
  52. == Authormate
  53. == Emailmate20201321@aliyun.com
  54. == PlatformA3352+EC20 R2.1
  55. ==========================================================
  56. == GPS state bit : A [A:有效状态 V:无效状态]
  57. == GPS mode bit : A [A:自主定位 D:差分定位]
  58. == Date : 2020-11-03
  59. == Time : 12:48:44
  60. == 纬度 : 北纬:315047
  61. == 经度 : 东经:1171718
  62. == 速度 : 1.400 kn(节)
  63. ==
  64. ==========================================================

二、GPS模组数据处理

GPS上电后,每隔一定的时间就会返回一定格式的数据,数据格式为:
$信息类型,x,x,x,x,x,x,x,x,x,x,x,x,x
每行开头的字符都是‘$’,接着是信息类型,后面是数据,以逗号分隔开。一行完整的数据如下:

  1. $GNGGA,093100.000,3151.10397,N,11707.63497,E,1,11,2.6,214.7,M,-5.0,M,,*50
  2. $GNGLL,3151.10397,N,11707.63497,E,093100.000,A,A*49
  3. $GNGSA,A,3,02,05,12,20,25,,,,,,,,3.9,2.6,2.9,1*35
  4. $GNGSA,A,3,10,13,28,33,38,41,,,,,,,3.9,2.6,2.9,4*36
  5. $GPGSV,3,1,10,02,60,349,39,05,38,247,41,06,49,057,27,12,30,263,31,0*65
  6. $GPGSV,3,2,10,13,,,24,17,17,143,,19,39,141,29,20,21,248,39,0*5F
  7. $GPGSV,3,3,10,25,15,299,44,195,,,26,0*6C
  8. $BDGSV,3,1,09,05,,,35,10,37,218,28,13,52,318,41,27,,,36,0*72
  9. $BDGSV,3,2,09,28,48,323,46,33,73,210,33,38,61,342,42,40,,,37,0*42
  10. $BDGSV,3,3,09,41,20,218,40,0*45
  11. $GNRMC,093100.000,A,3151.10397,N,11707.63497,E,0.00,0.00,280521,,,A,V*08
  12. $GNVTG,0.00,T,,M,0.00,N,0.00,K,A*23
  13. $GNZDA,093100.000,28,05,2021,00,00*4D
  14. $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)当前卫星信息

  1. $GPGSA,<1>,<2>,<3>,<3>,,,,,<3>,<3>,<3>,<4>,<5>,<6>,<7>
  2. <1>模式 M =手动, A =自动。
  3. <2>定位型式 1 =未定位, 2 =二维定位, 3 =三维定位。
  4. <3>PRN 数字:01 32表天空使用中的卫星编号,最多可接收12颗卫星信息。
  5. <4> PDOP位置精度因子(0.5-99.9
  6. <5> HDOP水平精度因子(0.5-99.9
  7. <6> VDOP垂直精度因子(0.5-99.9
  8. <7> Checksum.(检查位).

这里整条语句是一个文本行,行中以逗号“,”隔开各个字段,每个字段的大小(长度)不一,这里的示例只是一种可能,并不能认为字段的大小就如上述例句一样。

(2)GPS Satellites in View(GSV)可见卫星信息

  1. $GPGSV, <1>,<2>,<3>,<4>,<5>,<6>,<7>,?<4>,<5>,<6>,<7>,<8>
  2. <1> GSV语句的总数
  3. <2> 本句GSV的编号
  4. <3> 可见卫星的总数,0012
  5. <4> 卫星编号, 0132
  6. <5>卫星仰角, 0090度。
  7. <6>卫星方位角, 000359度。实际值。
  8. <7>讯号噪声比(C/No),00 99 dB;无表未接收到讯号。
  9. <8>Checksum.(检查位).
  10. 第<4>,<5>,<6>,<7>项个别卫星会重复出现,每行最多有四颗卫星。
  11. 其余卫星信息会于次一行出现,若未使用,这些字段会空白。

(3)Global Positioning System Fix Data(GGA)GPS定位信息

  1. $GPGGA,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,M,<10>,M,<11>,<12>*hh
  2. <1> UTC时间,hhmmss(时分秒)格式
  3. <2> 纬度ddmm.mmmm(度分)格式(前面的0也将被传输)
  4. <3> 纬度半球N(北半球)或S(南半球)
  5. <4> 经度dddmm.mmmm(度分)格式(前面的0也将被传输)
  6. <5> 经度半球E(东经)或W(西经)
  7. <6> GPS状态:0=未定位,1=非差分定位,2=差分定位,6=正在估算
  8. <7> 正在使用解算位置的卫星数量(00-12)(前面的0也将被传输)
  9. <8> HDOP水平精度因子(0.5-99.9
  10. <9> 海拔高度(-9999.9-99999.9
  11. <10> 地球椭球面相对大地水准面的高度
  12. <11> 差分时间(从最近一次接收到差分信号开始的秒数,如果不是差分定位将为空)
  13. <12> 差分站ID0000~1023(前面的0也将被传输,如果不是差分定位将为空)

hh——校验和(check sum),$与*之间的(不包括这两个字符)所有字符ASCII码的校验和(各字节做异或运算,得到校验和后,再转换16进制格式的ASCII字符。)

(4)Recommended Minimum Specific GPS/TRANSIT Data(RMC)推荐定位信息

  1. $GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>*hh
  2. <1> UTC时间,hhmmss(时分秒)格式
  3. <2> 定位状态,A=有效定位,V=无效定位
  4. <3> 纬度ddmm.mmmm(度分)格式(前面的0也将被传输)
  5. <4> 纬度半球N(北半球)或S(南半球)
  6. <5> 经度dddmm.mmmm(度分)格式(前面的0也将被传输)
  7. <6> 经度半球E(东经)或W(西经)
  8. <7> 地面速率(000.0-99.9节,前面的0也将被传输)
  9. <8> 地面航向(000.0-359.9度,以真北为参考基准,前面的0也将被传输)
  10. <9> UTC日期,ddmmyy(日月年)格式
  11. <10> 磁偏角(000.0-180.0度,前面的0也将被传输)
  12. <11> 磁偏角方向,E(东)或W(西)
  13. <12> 模式指示(仅NMEA0183 3.00版本输出,A=自主定位,D=差分,E=估算,N=数据无效)

hh——校验和(check sum),$与*之间的(不包括这两个字符)所有字符ASCII码的校验和(各字节做异或运算,得到校验和后,再转换16进制格式的ASCII字符。)

(5)Track Made Good and Ground Speed(VTG)地面速度信息

  1. $GPVTG,<1>,T,<2>,M,<3>,N,<4>,K,<5>*hh
  2. <1> 以真北为参考基准的地面航向(000-359度,前面的0也将被传输)
  3. <2> 以磁北为参考基准的地面航向(000-359度,前面的0也将被传输)
  4. <3> 地面速率(000.0-999.9节,前面的0也将被传输)
  5. <4> 地面速率(0000.0-1851.8公里/小时,前面的0也将被传输)
  6. <5> 模式指示(仅NMEA0183 3.00版本输出,A=自主定位,D=差分,E=估算,N=数据无效)

hh——校验和(check sum),$与*之间的(不包括这两个字符)所有字符ASCII码的校验和(各字节做异或运算,得到校验和后,再转换16进制格式的ASCII字符。)

2、GPS数据获取与解析

(1)根据协议定义GPS数据结构体

  1. typedef unsigned int UINT;
  2. /*$GPRMC,语句ID,表明该语句为Recommended Minimum Specific GPS/TRANSIT Data(RMC)*/
  3. typedef struct __gprmc__
  4. {
  5. UINT time_GT; /*<1> UTC时间,hhmmss(时分秒)格式 */
  6. char pos_state; /*<2> 定位状态,A=有效定位,V=无效定位 */
  7. float latitude; /*<3> 纬度ddmm.mmmm(度分)格式(前面的0也将被传输)) */
  8. char NorS; /*<4> 纬度半球N(北半球)或S(南半球) */
  9. float longitude; /*<5> 经度dddmm.mmmm(度分)格式(前面的0也将被传输) */
  10. char EorW; /*<6> 经度半球E(东经)或W(西经) */
  11. float speed; /*<7> 地面速率(000.0~999.9节,前面的0也将被传输) */
  12. float direction; /*<8> 地面航向(000.0~359.9度,以真北为参考基准,前面的0也将被传输) */
  13. UINT Recdate; /*<9> UTC日期,ddmmyy(日月年)格式 */
  14. float declination; /*<10> 磁偏角(000.0~180.0度,前面的0也将被传输) */
  15. char dd; /*<11> 磁偏角方向,E(东)或W(西) */
  16. char mode; /*<12> 模式指示(仅NMEA0183 3.00版本输出,A=自主定位,D=差分,E=估算,N=数据无效)*/
  17. }GPRMC;
  18. /*$GPGGA,语句ID,表明该语句为Recommended Minimum Specific GPS/TRANSIT Data(RMC)*/
  19. typedef struct __gpgga__
  20. {
  21. UINT time_GT; /*<1> UTC时间,hhmmss(时分秒)格式 */
  22. float latitude; /*<2> 纬度ddmm.mmmm(度分)格式(前面的0也将被传输)) */
  23. char NorS; /*<3> 纬度半球N(北半球)或S(南半球) */
  24. float longitude; /*<4> 经度dddmm.mmmm(度分)格式(前面的0也将被传输) */
  25. char EorW; /*<5> 经度半球E(东经)或W(西经) */
  26. unsigned char pos_state; /*<6> 定位状态,1=有效定位,0=无效定位 */
  27. unsigned char NumofSat; /*<7> 使用卫星数量,从00到12(第一个零也将传送) */
  28. float Lev_accu; /*<8> 水平精确度,0.5到99.9 */
  29. float Sea_level; /*<9> 天线离海平面的高度,-9999.9到9999.9米M指单位米 */
  30. float Geoid; /*<10> 大地水准面高度,-9999.9到9999.9米M指单位米 */
  31. char data_dura; /*<11> 差分GPS数据期限(RTCMSC-104),最后设立RTCM传送的秒数量 */
  32. char station_label; /*<12> 差分参考基站标号,从0000到1023(首位0也将传送)*/
  33. }GPGGA;

(2)通过串口获取GPS字符串数据

  1. int Get_GPS_Data(int fd_read, unsigned char *SavdBuf, size_t SavdBufSize )
  2. {
  3. char ReadBuf[GPS_LEN];
  4. GPRMC gprmc;
  5. memset(&gprmc, 0, sizeof(GPRMC));
  6. struct pollfd PollFd;
  7. PollFd.fd = fd_read;
  8. PollFd.events = POLLIN;
  9. if(poll(&PollFd,1,1) && (PollFd.revents & POLLIN) ) //等待数据s
  10. {
  11. memset(ReadBuf, 0, sizeof(ReadBuf));
  12. size_t ReadSize = read(PollFd.fd, ReadBuf, sizeof(ReadBuf));
  13. if(ReadSize <0)
  14. {
  15. perror("read error");
  16. return -1;
  17. }
  18. #if IS_DEBUG
  19. printf("ReadBuf:\n");
  20. printf("%s",ReadBuf);
  21. #endif
  22. memset(&gprmc, 0 , sizeof(gprmc));
  23. if( (Analyse_GPRMC_GPS(ReadBuf, ReadSize, &gprmc)== 0 ) && (gprmc.pos_state == 'A') )
  24. {
  25. GPS_Data_Resolve ( &gprmc , SavdBuf, SavdBufSize );
  26. #if IS_DEBUG
  27. Print_GPRMC_GPS(&gprmc);
  28. printf("纬度 = %f\n", Bytes2Float ( SavdBuf , sizeof(float)));
  29. printf("精度 = %f\n", Bytes2Float ( SavdBuf+sizeof(float)+sizeof(char) , sizeof(float)));
  30. #endif
  31. return 0;
  32. }
  33. else
  34. printf("Invalid location!\n");
  35. return -1;
  36. }
  37. else
  38. printf("NO GPS DATA!\n");
  39. return -1;
  40. }

(3)解析GPS数据字符串

  1. int Analyse_GPRMC_GPS (char *ReadBuf, size_t ReadSize, GPRMC *gps_data)
  2. {
  3. char *ptr=NULL;
  4. if(gps_data==NULL)
  5. return -1;
  6. if(strlen(ReadBuf)<10)
  7. return -1;
  8. /* 如果buff字符串中包含字符"$GPRMC"则将$GPRMC的地址赋值给ptr */
  9. if((ptr=strstr(ReadBuf,"$GPRMC"))==NULL)
  10. return -1;
  11. int i=0;
  12. for( i=0; i<ReadSize-(ptr-ReadBuf);i++) //查找一行$GPRMC数据的结尾(换行符)
  13. {
  14. if(ptr[i] == '\n') //说明是完整的一组"$GPRMC"数据,否则就丢弃
  15. break;
  16. }
  17. if(i == ReadSize-(ptr-ReadBuf))
  18. return -1;
  19. /* sscanf函数为从字符串输入,意思是将ptr内存单元的值作为输入分别输入到后面的结构体成员 */
  20. sscanf(ptr,"$GPRMC,%d.00,%c,%f,%c,%f,%c,%f,%f,%d,%f,%c,%c*",
  21. &(gps_data->time_GT), &(gps_data->pos_state),
  22. &(gps_data->latitude),&(gps_data->NorS), &(gps_data->longitude), &(gps_data->EorW),
  23. &(gps_data->speed), &(gps_data->direction), &(gps_data->Recdate),
  24. &(gps_data->declination), &(gps_data->dd), &(gps_data->mode));
  25. return 0;
  26. }

(4)GPS数据转为通信协议格式

image.png

  1. ssize_t GPS_Data_Resolve (GPRMC *gps_data, unsigned char *ResolvedBuf, size_t ResolvedBufMaxSize )
  2. {
  3. size_t PackagedDataSize = 0;
  4. unsigned char tempbuf[sizeof(float)] = { 0 };
  5. //纬度转为字节
  6. Float2Bytes ( gps_data->latitude, tempbuf ,sizeof(float));
  7. PackagedDataSize = PackingData( 1, ResolvedBuf, ResolvedBufMaxSize, PackagedDataSize ,tempbuf ,sizeof(float) );
  8. //保存南北纬字符
  9. ResolvedBuf[PackagedDataSize] = gps_data->NorS;
  10. PackagedDataSize++;
  11. //经度转为字节
  12. memset(tempbuf, 0, sizeof(float));
  13. Float2Bytes ( gps_data->longitude, tempbuf ,sizeof(float));
  14. PackagedDataSize = PackingData( 1, ResolvedBuf, ResolvedBufMaxSize, PackagedDataSize ,tempbuf ,sizeof(float) );
  15. //保存东西经字符
  16. ResolvedBuf[PackagedDataSize] = gps_data->EorW;
  17. PackagedDataSize++;
  18. //速度转为字节
  19. memset(tempbuf, 0, sizeof(float));
  20. Int2Bytes ((long)(gps_data->speed * 10), tempbuf , 2);
  21. PackagedDataSize = PackingData( 1, ResolvedBuf, ResolvedBufMaxSize, PackagedDataSize ,tempbuf ,2);
  22. return PackagedDataSize;
  23. }

(5)显示解析结果

  1. int Print_GPRMC_GPS (GPRMC *gps_data)
  2. {
  3. printf("\n\n");
  4. printf("==========================================================\n");
  5. printf("== Global Navigation Satellite System \n");
  6. printf("== Author : mate \n");
  7. printf("== Email : mate20201321@aliyun.com \n");
  8. printf("== Platform : A3352+EC20 R2.1 \n");
  9. printf("==========================================================\n");
  10. printf("== GPS state : %c [A:Available V:Void] \n", gps_data->pos_state);
  11. printf("== GPS mode : %c [A:Autonomic D:DGPS] \n", gps_data->mode);
  12. printf("== Date : 20%02d-%02d-%02d \n", gps_data->Recdate%100,(gps_data->Recdate%10000)/100,gps_data->Recdate/10000);
  13. printf("== Time : %02d:%02d:%02d \n", (gps_data->time_GT/10000+8)%24,(gps_data->time_GT%10000)/100,gps_data->time_GT%100);
  14. 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));
  15. 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));
  16. printf("== velocity : %.3f kn \n", gps_data->speed); //1kn = 0.5144444 m/s
  17. printf("==\n");
  18. printf("==========================================================\n");
  19. return 0;
  20. }