首先关于定位一些解释
通常在Android端地图相关用的最多的都是第三方的Sdkj进行二次开发,如百度,高德,World Wind ,arcgis等,对于手机自带的GPS芯片和国内的北斗芯片了解的相对较少,GPS在android中已经由android底层驱动封装好了,对于导航定位下面我先说基本的常识:

GNSS
NMEA协议
Rtcm协议
GPGGA数据
差分定位
GNSS:
一般指全球导航卫星系统,其实GNSS就是所有导航系统的统称。
GNSS:Global Navigation Satellite System(全球卫星导航系统)
GPS:Global Positioning System(全球定位系统)
GPS是美国的卫星导航系统。
俄罗斯的GLONASS
欧盟的Galileo
中国的北斗。这几大导航系统统称为GNSS。
全球导航卫星系统定位是利用一组卫星的伪距、星历、卫星发射时间等观测量来是的,同时还必须知道用户钟差。全球导航卫星系统是能在地球表面或近地空间的任何地点为用户提供全天候的3维坐标和速度以及时间信息的空基无线电导航定位系统。因此,通俗一点说如果你除了要知道经纬度还想知道高度的话,那么,必须对收到4颗卫星才能准确定位。

NMEA协议
NMEA协议是为了在不同的GPS导航设备中建立统一的RTCM(海事无线电技术委员会)标准,它最初是由美国国家海洋电子协会(NMEA—The NationalMarine Electronics Association)制定的。NMEA协议有0180、0182和0183这3种,0183可以认为是前两种的升级,也是目前使用最为广泛的一种。在实际使用中,如果只是接收GPS的输出.则只需两根信号线 GPS数据输出线和信号地线,可以直接将EIA-422输出通道两条信号线中的一条同计算机的Rs232C输入线相连。
GPS(全球定位系统)接收机与手持机之间的数据交换格式一般都由生产厂商缺省定制,其定义内容普通用户很难知晓,且不同品牌、不同型号的GPS接收机所配置的控制应用程序也因生产厂家的不同而不同。所以,对于通用GPS应用软件,需要一个统一格式的数据标准,以解决与任意一台GPS的接口问题。NMEA-0183数据标准就是解决这类问题的方案之一。NMEA协议是为了在不同的GPS导航设备中建立统一的RTCM(海事无线电技术委员会)标准,它最初是由美国国家海洋电子协会(NMEA—The NationalMarine Electronics Association)制定的。
NMEA协议有0180、0182和0183这3种,0183可以认为是前两种的升级,也是目前使用最为广泛的一种,本文主要在0183下进行梳理

GPGGA
GPGGA,GPS固定数据输出语句($GPGGA),这是一帧GPS定位的主要数据,也是使用最广的数据。
$GPGGA 语句包括17个字段:
语句标识头,世界时间,纬度,纬度半球,经度,经度半球,定位质量指示,使用卫星数量,HDOP-水平精度因子,椭球高,高度单位,大地水准面高度异常差值,高度单位,差分GPS数据期限,差分参考基站标号,校验和结束标记(用回车符和换行符),分别用14个逗号进行分隔。
格式例子如下:
$GPGGA,014434.70,3817.13334637,N,12139.72994196,E,4,07,1.5,6.571,M,8.942,M,0.7,0016*7B
该数据帧的结构及各字段释义如下:
GPGGA,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,M,<10>,M,<11>,<12>∗xxGPGGA,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,M,<10>,M,<11>,<12>∗xxGPGGA:起始引导符及语句格式说明(本句为GPS定位数据);
<1> UTC时间,格式为hhmmss.sss;
<2> 纬度,格式为ddmm.mmmm(第一位是零也将传送);
<3> 纬度半球,N或S(北纬或南纬)
<4> 经度,格式为dddmm.mmmm(第一位零也将传送);
<5> 经度半球,E或W(东经或西经)
<6> GPS状态, 0初始化, 1单点定位, 2码差分, 3无效PPS, 4固定解, 5浮点解, 6正在估算 7,人工输入固定值, 8模拟模式, 9WAAS差分
<7> 使用卫星数量,从00到12(第一个零也将传送)
<8> HDOP-水平精度因子,0.5到99.9,一般认为HDOP越小,质量越好。
<9> 椭球高,-9999.9到9999.9米
M 指单位米
<10> 大地水准面高度异常差值,-9999.9到9999.9米M 指单位米
<11> 差分GPS数据期限(RTCM SC-104),最后设立RTCM传送的秒数量,如不是差分定位则为空
<12> 差分参考基站标号,从0000到1023(首位0也将传送)。
1. 语句结束标志符xx 从$开始到*之间的所有ASCII码的异或校验
回车符,结束标记
换行符,结束标记

RTCM
TCM全名国际海运事业无线电技术委员会,是国际标准组织。
NMEA 0183是美国国家海洋电子协会(National Marine Electronics Association )为海用电子设备制定的标准格式。目前业已成了GPS导航设备统一的RTCM(Radio Technical Commission for Maritime services)标准协议。也叫作差分站。

RTCM3.1数据格式及内容
CM3.1协议规范包括应用层、表示层、传输层、数据链路层和物理层。对于编解码最重要的是表示层和传输层。
应用层
描述了RTCM3.1协议中各类差分电文采用单向数据链广播给各类用户,用户如何利用差分电文实现高精度定位、测距以及各类拓展应用,如何提供高精度的定位和导航服务;阐述了普通定位系统与差分定位应用系统之间的精度差别,以及在测距、定位、导航等应用系统中发挥的明显优势。
表示层
表示层规定了差分的具体协议和电文格式,其数据架构包括两个主要方面,即数据字段和消息类型,包括消息、数据要素和数据定义。RTCM3.1中所涉及的实时动态定位消息分为若干个组,每个组又含有不同的子类,描述这些数据的是消息类型。
传输层

传输层定义了发送或接收RTCM3.1文电的帧结构,并详细介绍了差错控制算法(CRC校验算法)。差分电文是以二进制的形式进行传输的,定义该层是为了使RTCM10403.1的数据能够被正确解码。
通过网络传输的差分电文是按电文帧的形式进行,电文帧格式定义在物理层上的传输格式,目的是保证在应用中能被正确的解码,在数据传输过程中,差分电文提供者应把电文打包成一个个独立结构的帧,以使帧的传输最好适应这种传输方法。在传送到应用层之前,数据设置应该将这种帧的结构进行重建。基本的帧结构包含一个固定的前缀,一个电文长度定义,一组电文,和24比特循环冗余码校验(CRC),校验码是用于差错控制和保证每帧信息完整性的有效手段。帧格式的结构下图所示。

文件头    保留    电文长度    可变长度数据电文    CRC
8bits    6bits    10bits    电文字节的整数个数    24bits
11010011    未定义-设置为000000    按字节算的电文长度    0-1023字节    CRC-24Q
电文头是一个固定的8比特序列;接着的6个比特是保留的,设置成0;接着是可变长度电文的长度;接着是变长电文;最后是CRC校验码。如果数据链接需要短电文以保持一个连续的数据流,那么可变长度数据电文应该被设置为0,提供一个长度为48比特的填充电文。24比特的CRC奇偶性提供针对突发性错误和随机性错误的保护。CRC对连续字节的操作开始于文件头,直到可变长度电文域的结尾。24比特(p1,p2,…,p24)的顺序是按照信息比特(m1,m2, …,m8N)的顺序产生的,其中N是构成电文加上文件头和电文长度定义参数的序列的字节总数。

RTCM3.1解码
解码即按照版本定义将各字段数据取出并解出原数据。以1004电文的解码为例介绍解码的思路和过程。
1004是GPS RTK Message(1001-1004)的一种消息类型,它提供了卫星的载波、伪距和信噪比等信息,是观测文件的主要内容。GPS RTK Message在可变长度消息的开始有8个字节的消息头,其内容及字段定义在表4中列出。
1004电文的内容如表5所示,与其他类型信息不同,可变长度消息可能有N条1004电文,每条电文长度为125位,其长度不是字节位数的整数倍。为了提高利用率,每两条1004电文中间没有多余的位,如第一条电文的最后一个字节空余3位,则第二条电文补足,即最后3位是下一条电文开始的3位。这种排列为解码带来不便,因为数据是按字节读取,无法直接设循环解每条电文。注意到电文的排列还是有一定规律,解码的核心是编制一种方法,能够在字节数组中,以任意位为起始,取出所需比特位,这样就可以根据报文结构,在字节数组中获取数据,重构报文内容,然后就可以根据报文条数设置循环,对报文逐条进行相应处理。

差分定位
差分定位也叫差分GPS技术,即将一台GPS接收机安置在基准站上进行观测。根据基准站已知精密坐标,计算出基准站到卫星的距离改正数,并由基准站实时将这一数据发送出去。用户接收机在进行GPS观测的同时,也接收到基准站发出的改正数,并对其定位结果进行改正,从而提高定位精度。
差分定位(Differential positioning),也叫相对定位,是根据两台以上接收机的观测数据来确定观测点之间的相对位置的方法,它既可采用伪距观测量也可采用相位观测量,大地测量或工程测量均应采用相位观测值进行相对定位。
可以简单的理解为在已知坐标的点上安置一台GPS接收机(称为基准站),利用已知坐标和卫星星历计算出观测值的校正值,并通过无线电设备(称数据链)将校正值发送给运动中的GPS接收机(称为流动站),流动站应用接收到的校正值对自己的GPS观测值进行改正,以消除卫星钟差钟差、接收机钟差、大气电离层和对流层折射误差的影响。
这部分很专业,具体可以查资料

在Android中获取GPS中的NMEA-0183协议中的GPGGA数据,再获取经纬度
public class MainActivity extends AppCompatActivity {
    private TextView tvWGS84, tvNmea;
    private LocationListener gpsListener;
    private LocationManager mLocationManager;
    private GeomagneticField gmfield;

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //显示wgs84数据
        tvWGS84 = (TextView) findViewById(R.id.tv_rgs84);
        //显示nmea协议中数据
        tvNmea = (TextView) findViewById(R.id.tv_nmea);
        mLocationManager = ((LocationManager) getSystemService(Context.LOCATION_SERVICE));
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions
            // here to request the missing permissions, and then overriding
            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
            //                                          int[] grantResults)
            // to handle the case where the user grants the permission. See the documentation
            // for ActivityCompat#requestPermissions for more details.
            return;
        }
        mLocationManager.addNmeaListener(new GpsStatus.NmeaListener() {

@Override
            public void onNmeaReceived(long timestamp, String nmea) {
                tvNmea.invalidate();
                //此处以GPGGA为例
                //$GPGGA,232427.000,3751.1956,N,11231.1494,E,1,6,1.20,824.4,M,-23.0,M,,*7E
                if (nmea.contains("GPGGA")) {
                    String info[] = nmea.split(",");
                    //GPGGA中altitude是MSL altitude(平均海平面)
                    tvWGS84.setText(nmea);
                    Log.i("GPGGA","获取的GPGGA数据是:"+nmea);
                    Log.i("GPGGA","获取的GPGGA数据length:"+info.length);
                    Log.i("GPGGA","GPS定位数据:"+info[0]);
                    Log.i("GPGGA","UTC时间:"+info[1]);

Log.i("GPGGA","纬度:"+info[2]);
                    Log.i("GPGGA","纬度半球:"+info[3]);
                    Log.i("GPGGA","经度:"+info[4]);
                    Log.i("GPGGA","经度半球:"+info[5]);
                    Log.i("GPGGA","GPS状态:"+info[6]);
                    Log.i("GPGGA","使用卫星数量:"+info[7]);
                    Log.i("GPGGA","HDOP-水平精度因子:"+info[8]);
                    Log.i("GPGGA","椭球高:"+info[9]);
                    Log.i("GPGGA","大地水准面高度异常差值:"+info[10]);
                    Log.i("GPGGA","差分GPS数据期限:"+info[11]);
                    Log.i("GPGGA","差分参考基站标号:"+info[12]);
                    Log.i("GPGGA","ASCII码的异或校验:"+info[info.length-1]);
                    //UTC + (+0800) = 本地(北京)时间
                    int a= Integer.parseInt(info[1].substring(0,2));
                    a+=8;
                    a%=24;
                    String time="";
                    String time1="";
                    if(a<10){
                        time="0"+a+info[1].substring(2,info[1].length()-1);
                    }
                    else{
                        time=a+info[1].substring(2,info[1].length()-1);
                    }
                    time1=time.substring(0,2)+":"+time.substring(2,4)+":"+time.substring(4,6);
                    tvNmea.setText("获取的GPGGA数据length:"+info.length+"\nUTC时间:"+info[1]+"\n北京时间: "+time1
                    +"\n纬度:"+info[2]+"\n纬度半球:"+info[3]+"\n经度:"+info[4]+"\n经度半球:"+info[5]
                    +"\nGPS状态:"+info[6]+"\n使用卫星数量:"+info[7]+"\nHDOP-水平精度因子:"+info[8]+"\n椭球高:"+info[9]
                    +"\n大地水准面高度异常差值:"+info[10]+"\n差分GPS数据期限:"+info[11]+"\n差分参考基站标号:"+info[12]
                    +"\nASCII码的异或校验:"+info[info.length-1]);
                }
            }
        });
        gpsListener = new MyLocationListner();
    }

private class MyLocationListner implements LocationListener {

@RequiresApi(api = Build.VERSION_CODES.CUPCAKE)
        @Override
        public void onLocationChanged(Location location) {
            tvWGS84.invalidate();
            tvNmea.invalidate();
            Double longitude = location.getLongitude();
            float accuracy = location.getAccuracy();
            Double latitude = location.getLatitude();
            Double altitude = location.getAltitude();// WGS84
            float bearing = location.getBearing();
            gmfield = new GeomagneticField((float) location.getLatitude(),
                    (float) location.getLongitude(), (float) location.getAltitude(),
                    System.currentTimeMillis());
            tvWGS84.setText("Altitude=" + altitude + "\nLongitude=" + longitude + "\nLatitude="
                    + latitude + "\nDeclination=" + gmfield.getDeclination() + "\nBearing="
                    + bearing + "\nAccuracy=" + accuracy);
        }

@Override
        public void onStatusChanged(String provider, int status, Bundle extras) {

}

@Override
        public void onProviderEnabled(String provider) {

}

@Override
        public void onProviderDisabled(String provider) {

}

}

@Override
    protected void onPause() {
        super.onPause();
        //退出Activity后不再定位
        mLocationManager.removeUpdates(gpsListener);
    }

@Override
    protected void onResume() {
        super.onResume();
        //判断gps是否可用
        if (mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
            Toast.makeText(this, "gps可用", Toast.LENGTH_LONG).show();
            //开始定位
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                // TODO: Consider calling
                //    ActivityCompat#requestPermissions
                // here to request the missing permissions, and then overriding
                //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
                //                                          int[] grantResults)

// to handle the case where the user grants the permission. See the documentation
                // for ActivityCompat#requestPermissions for more details.
                return;
            }
            mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 10, gpsListener);
        }else{
            Toast.makeText(this, "请打开gps或者选择gps模式为准确度高", Toast.LENGTH_LONG).show();
            //前往设置GPS页面
            startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
        }
    }
}

Android 关于定位中的那点事(GPS,GPGGA,NMEA-0183,RTCM)相关推荐

  1. android经纬度是4.9e-324,百度定位中出现4.9E-324问题的原因和解决办法

    百度定位请查看官方开发文档 定位过程中出现经纬度为4.9E-324错误的可能情况,目前收集到四种: 1.权限错误 什么是权限错误呢?分为两种情况: 一是权限没有添加完全,没有从开发文档中完全拷贝到项目 ...

  2. android百度定位失败的原因,百度定位中出现4.9E-324问题的原因和解决办法

    百度定位请查看官方开发文档 定位过程中出现经纬度为4.9E-324错误的可能情况,目前收集到四种: 1.权限错误 什么是权限错误呢?分为两种情况: 一是权限没有添加完全,没有从开发文档中完全拷贝到项目 ...

  3. Android中那些有你不知道的事

    在安卓开发中,总有那么一些看似简单,实则绊脚的难题,等你去探索,等你去解决,也许你已经遇见了解决了,也许你还没碰上,写下这篇总结,希望能帮助那行即将遇到的朋友,快速解决这些小问题! 一.activit ...

  4. android vector 圆形,Android中矢量图形的那些事 - SVG or Vector

    之前对矢量图形有所耳闻,但因为Android对于矢量图形的原生支持较晚,所以一直没好好研究过(16年2月25就出来的东西,其实就是懒 =.=).最近工作上正好遇到一个产品需求,想用SVG来解决,借此机 ...

  5. android删除历史定位,android - 从历史记录中删除活动

    android - 从历史记录中删除活动 我的应用在用户首次运行应用时显示了注册活动,如下所示: 活动启动画面(欢迎使用游戏,注册帐户?) ActivitySplashScreenSignUp(很棒, ...

  6. 豁然开朗篇:安卓开发中关于虚拟机那些事

    彻底搞懂虚拟机这一块,看这一篇就够了 前言 作为豁然开朗篇的最终篇,本文要讲解的是虚拟机这块,因为在之前讲解内存与线程的时候,一直都会牵涉到虚拟机和指令集这块,所以,为了让大家再豁然开朗多一次,本文会 ...

  7. Android学习-- 基于位置的服务 LBS(基于百度地图Android SDK)--定位SDK

    原文:Android学习-- 基于位置的服务 LBS(基于百度地图Android SDK)--定位SDK 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.ne ...

  8. Android App定位和规避内存泄露方法研究

    from:http://site.douban.com/android/widget/notes/350758/note/167481484/ 工作中刚好用到,网上搜到的,觉得不错,与大家分享 And ...

  9. Android基站定位

    Android基站定位   一.通过手机信号获取基站信息 通过TelephonyManager 获取lac:mcc:mnc:cell-id(基站信息)的解释: MCC,Mobile Country C ...

  10. 在 Android 应用程序中使用 Internet 数据

    为什么80%的码农都做不了架构师?>>>    简介: 您的很多 Android 应用程序都需要与 Internet 数据交互,这些数据采用各种格式.本文将带您构建一个 Androi ...

最新文章

  1. SAP ABAP的权限检查跟踪(Authorization trace)工具使用步骤介绍
  2. Android学习笔记篇2. 单选按钮、复选按钮
  3. js中关于Blob对象的介绍与使用
  4. 关于Linq to DataSet
  5. 阿里云容器服务发布 Knative 托管服务
  6. 云存储精华问答 | 如何选择混合云提供商?
  7. linux echo输出转义换行回车引号
  8. 修复 www.shouyela.com 造成的 IE 问题
  9. Linux命令 查看端口占用情况
  10. Vue3+Vite项目配置Eslint+Prettier+Husky+Lint-Staged+Commitlint
  11. 鸿蒙OS原子化服务卡片原理和架构分析
  12. 纯电动汽车两档ATM变速箱simulink模型,模型实现了两档AMT换挡策略和换挡过程仿真
  13. Java基础语法总结(一)——类与对象
  14. 国产EDA工具Robei与Quartus ii联合使用(及在Rrobei设计中一些小技巧)
  15. iocp端口断开_在完成端口IOCP模型判断客户端是否已关闭连接(掉线) | 学步园
  16. 一岁半小朋友的火星电话和滑滑梯
  17. prism RegionContext(区域上下文)
  18. 基于tensorflow的mnist数据集手写字体分类level-1
  19. ubuntu 16.04 文件打包成deb文件的方法
  20. 如何设置linux lang环境变量,设置linux环境变量LANG(示例代码)

热门文章

  1. 病毒木马防御与分析实战 1
  2. SPSS教程及常用操作参考表 —— 一篇文章解决对SPSS的所有疑问
  3. Nexus3搭建本地仓库
  4. java qq机器人_简单几步教你如何用Java快速制作一个QQ机器人
  5. SpringCloud Nacos 【服务端】服务注册源码解析
  6. java 正则表达式 html,java正则表达式语法大全
  7. java正则表达式http_Java 正则表达式(精华)
  8. 一阶滤波算法公式推导
  9. 光谱共焦位移传感器原理
  10. linux汉诺塔实验报告,汉诺塔问题实验报告