GPS经纬度坐标转换

在淘宝买的ATGM336H
用串口工具在室外读取了下面的数据

这些字符串是GPS定位设备输出的NMEA 0183格式的数据。
NMEA 0183是一种用于在船舶、飞机和其他移动设备中传输位置、速度和时间等信息的标准协议。


$BDGSV,39,,,27*62 22:29:38.654 
$GNRMC,142939.000,A,3036.7460,K,A*23 22:29:38.754
$GNZDA,142939.000,31,03,2024,00,00*49 22:29:38.858 
$GPTXT,01,01,0
$GNGGA,142940.000,3036.74671,N,10408.54235,E,1,07,1.2,573.5,M,0.0,M,,*75 22:29:38.958 
$GNGLL,3036.74671,N,10408.54235,E,142940.000,A,A*40 22:29:39.061 
$GPGSA,A,3,05,15,20,23,29,195,,,,,,,2.2,1.2,1.9*0D 22:29:39.161 
$BDGSA,A,3,19,,,,,,,,,,,SV,3,1,09,05,33,064,32,10,,,27,13,40,04,216,37*48 22:29:39.263 -> $GPGSV,3,3,09,195,42,139,19*78 22:29:39.366
$BDGSV,1,1,04,02,,,33,09,,,29,19,45,275,33,39,,,27*5A 22:29:39.468 
$GNRMC,142940.000,A,3036.74671,N,10408.54235,E,0.00,0.00,310324,,,A*70 

比较有用的是GNGGA,有经纬度,有卫星数,有海拔之类的信息

但是他使用的数据需要转换先转换成WGS84再转换成GCJ02
而百度地图/高德地图的一般接受GCJ02

1.获取对应串口数据的经纬度(这里是C代码)

//主要是靠索引来查询找到数据
void GPSTask(void *parameter){
  for(;;){
    delay(100); 
    String GpsMsg=Serial2.readStringUntil('\n');
    Serial.println(GpsMsg);
    int isIndex=GpsMsg.indexOf("$GNRMC");
    if (isIndex==-1){
      continue;
    }
    lon = extractLongitude(GpsMsg);
    lat = extractLatitude(GpsMsg);
    
  }
}

// 提取经度信息
float extractLongitude(String nmea) {
  int pos = 0; // 找到第一个逗号的位置
  for (int i = 0; i < 5; i++) {
    pos = nmea.indexOf(",", pos) + 1; // 找到第三个逗号的位置
    if (pos==-1){
      return 0;
    }
  }
  String longitudeStr = nmea.substring(pos, nmea.indexOf(",", pos));
  if (longitudeStr==""){
    return 0;
  }
  float longitude = longitudeStr.toFloat();
  return longitude;
}

// 提取纬度信息
float extractLatitude(String nmea) {
  int pos = 0; // 找到第一个逗号的位置
  for (int i = 0; i < 3; i++) {
    pos = nmea.indexOf(",", pos) + 1; // 找到第五个逗号的位置
     if (pos==-1){
      return 0;
    }
  }
  String latitudeStr = nmea.substring(pos, nmea.indexOf(",", pos));
   if (latitudeStr==""){
    return 0;
  }
  float latitude = latitudeStr.toFloat();
  return latitude;
}

2.将串口的数据转成WGS84


    public static double[] SerialtoWGS84(String lng, String lat) {

        int lngIndex = lng.indexOf(".") - 2;
        int latIndex = lat.indexOf(".") - 2;
        if (lngIndex < 0 || latIndex < 0){
        return null;
        }
        double lngDouble1 = Double.parseDouble(lng.substring(0, lngIndex));
        double lngDouble2 = Double.parseDouble(lng.substring( lngIndex));
        double lngDouble = lngDouble1 + lngDouble2 / 60;

        double latDouble1 = Double.parseDouble(lat.substring(0, latIndex));
        double latDouble2 = Double.parseDouble(lat.substring( latIndex));
        double latDouble = latDouble1 + latDouble2 / 60;
        if (lngDouble > 0 && latDouble > 0){
            return new double[]{lngDouble, latDouble};
        }
        return null;
    }

3.将WGS84的数据转成GCJ02

 public static double ee = 0.00669342162296594323;  //偏心率平方
    public static double a = 6378245.0;//  # 长半轴


    /**
     * GPS84转GCJ02(火星坐标系)
     *
     * @param lng_wgs WGS84坐标系的经度
     * @param lat_wgs WGS84坐标系纬度
     * @return 转换后的GCJ02下经纬度
     */
    public static double[] WGS84toGCJ02(double lng_wgs, double lat_wgs) {
        if (outOfChina(lng_wgs, lat_wgs)) {
            return new double[]{lng_wgs, lat_wgs};
        }
        double[] GCJ02 = new double[2];

        double dlat = transformlat(lng_wgs - 105.0, lat_wgs - 35.0);
        double dlng = transformlng(lng_wgs - 105.0, lat_wgs - 35.0);
        double radlat = lat_wgs / 180.0 * Math.PI;
        double magic = Math.sin(radlat);
        magic = 1 - ee * magic * magic;
        double sqrtmagic = Math.sqrt(magic);
        dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * Math.PI);
        dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * Math.PI);
        double gcj_lat = lat_wgs + dlat;
        double gcj_lng = lng_wgs + dlng;
        GCJ02[0] = gcj_lng;
        GCJ02[1] = gcj_lat;
        return GCJ02;
    }


    private static double transformlat(double lng, double lat) {
        double ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat +
                0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng));
        ret += (20.0 * Math.sin(6.0 * lng * Math.PI) + 20.0 *
                Math.sin(2.0 * lng * Math.PI)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(lat * Math.PI) + 40.0 *
                Math.sin(lat / 3.0 * Math.PI)) * 2.0 / 3.0;
        ret += (160.0 * Math.sin(lat / 12.0 * Math.PI) + 320 *
                Math.sin(lat * Math.PI / 30.0)) * 2.0 / 3.0;
        return ret;
    }

    private static double transformlng(double lng, double lat) {
        double ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng +
                0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng));
        ret += (20.0 * Math.sin(6.0 * lng * Math.PI) + 20.0 *
                Math.sin(2.0 * lng * Math.PI)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(lng * Math.PI) + 40.0 *
                Math.sin(lng / 3.0 * Math.PI)) * 2.0 / 3.0;
        ret += (150.0 * Math.sin(lng / 12.0 * Math.PI) + 300.0 *
                Math.sin(lng / 30.0 * Math.PI)) * 2.0 / 3.0;
        return ret;
    }

    /**
     * 判断是否在国内,不在国内不做偏移
     *
     * @param lng
     * @param lat
     * @return
     */
    private static boolean outOfChina(double lng, double lat) {
        return !(lng > 73.66 && lng < 135.05 && lat > 3.86 && lat < 53.55);
    }

WGS84:地球坐标系,是国际上通用的坐标系,设备一般包含GPS芯片或者北斗芯片获取的经纬度为WGS84地理坐标系

GCJ02:火星坐标系,是由中国国家测绘局制订的地理信息系统的坐标系统。在中国使用的地图产品使用的都必须是加密后的坐标
  1. $BDGSV,39,27*62 22:29:38.654:BDGSV表示北斗卫星的可见卫星信息,39表示总共有39颗卫星,但是这个字符串中没有提供具体的卫星信息。

  2. $GNRMC,142939.000,A,3036.7460,K,A*23 22:29:38.754:GNRMC表示推荐的最小定位信息,142939.000表示定位时间,A表示定位有效,3036.7460表示纬度,K表示速度单位为千米/小时,A表示方向有效。

  3. $GNZDA,142939.000,31,03,2024,00,00*49 22:29:38.858:GNZDA表示日期和时间信息,142939.000表示时间,31表示日期,03表示月份,2024表示年份,00表示本地时区的小时偏移量,00表示本地时区的分钟偏移量。

  4. $GPTXT,01,01,0:GPTXT表示文本信息,这个字符串中没有提供具体的文本内容。

  5. $GNGGA,142940.000,3036.74671,N,10408.54235,E,1,07,1.2,573.5,M,0.0,M,*75 22:29:38.958:GNGGA表示全球定位系统定位信息,142940.000表示定位时间,3036.74671表示纬度,N表示北纬,10408.54235表示经度,E表示东经,1表示定位质量指示,07表示使用的卫星数量,1.2表示水平精度因子,573.5表示海拔高度,M表示单位为米,0.0表示大地水准面的高度,M表示单位为米。

  6. $GNGLL,3036.74671,N,10408.54235,E,142940.000,A,A*40 22:29:39.061:GNGLL表示地理定位信息,3036.74671表示纬度,N表示北纬,10408.54235表示经度,E表示东经,142940.000表示定位时间,A表示定位有效,A表示数据来源为GPS。

  7. $GPGSA,A,3,05,15,20,23,29,195,2.2,1.2,1.9*0D 22:29:39.161:GPGSA表示GNSS DOP和活动卫星信息,A表示自动选择2D/3D定位模式,3表示定位模式为3D定位,05、15、20、23、29、195表示使用的卫星编号,2.2表示PDOP(位置精度因子),1.2表示HDOP(水平精度因子),1.9表示VDOP(垂直精度因子)。

  8. $BDGSA,A,3,19,SV,3,1,09,05,33,064,32,10,27,13,40,04,216,3748 22:29:39.263 -> $GPGSV,3,3,09,195,42,139,1978 22:29:39.366:BDGSA表示北斗卫星的DOP和活动卫星信息,A表示自动选择2D/3D定位模式,3表示定位模式为3D定位,19表示使用的卫星编号,SV表示卫星编号的开始,3表示卫星编号的数量,1、09、05、33、064、32、10、27、13、40、04、216、37表示具体的卫星编号。

  9. $BDGSV,1,1,04,02,33,09,29,19,45,275,33,39,27*5A 22:29:39.468:BDGSV表示北斗卫星的可见卫星信息,1表示总共有1颗卫星,1表示当前是第1个字符串,04表示总共有4个字符串,02、33、09、29、19、45、275、33、39、27表示具体的卫星信息。

  10. $GNRMC,142940.000,A,3036.74671,N,10408.54235,E,0.00,0.00,310324,A*70:GNRMC表示推荐的最小定位信息,142940.000表示定位时间,A表示定位有效,3036.74671表示纬度,N表示北纬,10408.54235表示经度,E表示东经,0.00表示速度,0.00表示方向,310324表示日期,A表示数据来源为GPS。

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值