【模块】北斗+GPS双模定位模块

article/2025/9/19 6:55:57

在相当长的时间里,GNSS(全球卫星导航系统, Global Navigation Satellite System)是以美国的GPS(Global Positioning System, 全球定位系统)一家独大的。随着各国对定位系统的逐渐重视,都陆续推出自己的卫星导航系统,比如我国的北斗、俄罗斯的GLONASS还有欧盟的伽利略。

研究并建成一套拥有完全独立自主技术的卫星导航系统是相当不容易的,我国举全国之力为之奋斗了整整26年。今年的7月31号,北斗三号正式开通标志着中国可以摆脱GPS系统的掣肘,真正地走向全球,对中国来说意义非凡。

本篇文章里小编并不想详细的比较北斗和GPS系统之间的差异和优劣,网络上有很多专业的比较,感兴趣的同学可以自行搜索。我们更感兴趣的当然是作为民用级别的定位应用,怎么白嫖最方便和最精确?

比如说你想在自己DIY的项目中加入定位模块,一搜索你会发现市面上大多是多模(双模或者三模)定位模块,很少会有北斗单模系统。原因有以下几个:

  1.  虽然北斗也有民用频段,但普及程度没有GPS广,比如Arduino的北斗示例和资料都比较少。

  2. 其实北斗、GPS、伽利略和GLONASS的民用射频频段几乎是一样,模块厂家只需要一块射频接收器,后端稍作不同的处理就可以支持不同的系统并不需要增加额外的成本,所以厂家更愿意推广多模的模块,比如北斗/BDS和GPS双模。

  3. 民用级别的双模在精度上被证明的确优于单模。最主要的原因就是多一套系统,可用的卫星数就多了。下面三张图就是网友(知乎@侯燕青)实测的对比图(红色为实际轨迹)。

接下去我们就来实际操作一下,如何用Arduino读取北斗+GPS双模定位模块的数据。

我们使用的是型号为ATGM336H-5N模块,这是一款非常小尺寸的、支持全GNSS系统(北斗、GPS、GLONASS、伽利略、日本的QZSS以及卫星增强系统SBAS),ATGM336H-5N模块基于中科微AT6558单芯片,价格也很美丽。

首先把模块的引脚焊接上,并接好陶瓷天线。模块是通过UART跟Arduino交流的,如果对UART协议不了解,请参阅《Arduino常用的三种通信协议UART, I2C和SPI》。按照下图的对应关系,我们连接好模块和Arduino UNO,PPS可不接。

#include <SoftwareSerial.h> SoftwareSerial sSerial(12, 11); //RX,TXvoid setup(){     Serial.begin(115200);  //Debug Serial   sSerial.begin(9600);  //Gps Serial   }
void loop(){  while (sSerial.available() > 0)  {     byte gpsData = sSerial.read();     Serial.write(gpsData);   }}

这里解释一下,因为我们需要创建一个软串口(SoftwareSerial)用于Arduino和模块之间的通信,而默认的硬串口Serial用于串口监视器查看具体的输出数据。

通上电,打开Arduino串口监视器,如果一切正常,你将会看到类似下面的一堆火星文。

这些火星文就是NMEA-0183协议的报文,大多数常见的GNSS接收机、GNSS数据处理软件、导航软件都遵守或者至少兼容这个协议。

数据里面我们看到三种数据类型 GN、GP、BD 分别代表双模模式、GPS 模式、北斗模式。那比如下面这条报文怎么理解呢?

$GNGGA,064954.000,3040.04684,N,10348.56480,E,1,09,1.7,491.2,M,0.0,M,,*71

根据NMEA-0183协议的规定,$XXGGA报文是关于时间、经纬度位置、解算状态、卫星颗数等相关信息。XX的不同代表模式的不同,比如$GPGGA表示单GPS模式,$BDGGA表示单北斗模式,$GNGGA表示多星联合定位。具体的含义我们对应查表就行了:

还有其他的报文都有对应的含义:

$XXGSA 显示的是当前的卫星信息:

$XXGSV 显示的是可见卫星的信息:

每条GSV语句最多可以显示4个可见卫星的信息,其他的卫星都会在下一条语句中输出显示。每种卫星系统都会单独显示,一般GPS有3条GSV报文,北斗有2条GSV报文。

$XXVTG包含地面速度信息:

$XXGLL包含基本的地理定位信息:

$XXRMC包含位置、速度、时间等最简定位信息:

如果我们不想把NMEA-0183协议的报文一股脑儿地输出,我们可以把之Arduino的代码再写复杂一点,把数据解析也做一下再输出:

#include <SoftwareSerial.h>SoftwareSerial sSerial(12, 11);  //RX,TX
struct{  char GPS_Buffer[80];  bool isGetData;    //是否获取到GPS数据  bool isParseData;  //是否解析完成  char UTCTime[11];    //UTC时间  char latitude[11];    //纬度  char N_S[2];    //N/S  char longitude[12];    //经度  char E_W[2];    //E/W  bool isUsefull;    //定位信息是否有效} Save_Data;
const unsigned int gpsRxBufferLength = 600;char gpsRxBuffer[gpsRxBufferLength];unsigned int ii = 0;void setup()  //初始化内容{  sSerial.begin(9600);      //定义波特率9600  Serial.begin(115200);    Serial.println("I Love Arduino");  Serial.println("Wating...");Save_Data.isGetData = false;  Save_Data.isParseData = false;  Save_Data.isUsefull = false;}
void loop()    //主循环{  gpsRead();  //获取GPS数据  parseGpsBuffer();//解析GPS数据  printGpsBuffer();//输出解析后的数据}
void errorLog(int num){  Serial.print("ERROR");  Serial.println(num);  while (1)  {    digitalWrite(13, HIGH);    delay(300);    digitalWrite(13, LOW);    delay(300);  }}
void printGpsBuffer(){  if (Save_Data.isParseData)  {    Save_Data.isParseData = false;        Serial.print("Save_Data.UTCTime = ");    Serial.println(Save_Data.UTCTime);if(Save_Data.isUsefull)    {      Save_Data.isUsefull = false;      Serial.print("Save_Data.latitude = ");      Serial.println(Save_Data.latitude);      Serial.print("Save_Data.N_S = ");      Serial.println(Save_Data.N_S);      Serial.print("Save_Data.longitude = ");      Serial.println(Save_Data.longitude);      Serial.print("Save_Data.E_W = ");      Serial.println(Save_Data.E_W);    }    else    {      Serial.println("GPS DATA is not usefull!");    }      }}
void parseGpsBuffer(){  char *subString;  char *subStringNext;  if (Save_Data.isGetData)  {    Save_Data.isGetData = false;    Serial.println("**************");    Serial.println(Save_Data.GPS_Buffer);for (int i = 0 ; i <= 6 ; i++)    {      if (i == 0)      {        if ((subString = strstr(Save_Data.GPS_Buffer, ",")) == NULL)          errorLog(1);  //解析错误      }      else      {        subString++;        if ((subStringNext = strstr(subString, ",")) != NULL)        {          char usefullBuffer[2];           switch(i)          {            case 1:memcpy(Save_Data.UTCTime, subString, subStringNext - subString);break;  //获取UTC时间            case 2:memcpy(usefullBuffer, subString, subStringNext - subString);break;  //获取UTC时间            case 3:memcpy(Save_Data.latitude, subString, subStringNext - subString);break;  //获取纬度信息            case 4:memcpy(Save_Data.N_S, subString, subStringNext - subString);break;  //获取N/S            case 5:memcpy(Save_Data.longitude, subString, subStringNext - subString);break;  //获取纬度信息            case 6:memcpy(Save_Data.E_W, subString, subStringNext - subString);break;  //获取E/Wdefault:break;          }subString = subStringNext;          Save_Data.isParseData = true;          if(usefullBuffer[0] == 'A')            Save_Data.isUsefull = true;          else if(usefullBuffer[0] == 'V')            Save_Data.isUsefull = false;}        else        {          errorLog(2);  //解析错误        }      }    }  }}void gpsRead() {  while (sSerial.available())  {    gpsRxBuffer[ii++] = sSerial.read();    if (ii == gpsRxBufferLength)clrGpsRxBuffer();  }char* GPS_BufferHead;  char* GPS_BufferTail;  if ((GPS_BufferHead = strstr(gpsRxBuffer, "$GPRMC,")) != NULL || (GPS_BufferHead = strstr(gpsRxBuffer, "$GNRMC,")) != NULL )  {    if (((GPS_BufferTail = strstr(GPS_BufferHead, "\r\n")) != NULL) && (GPS_BufferTail > GPS_BufferHead))    {      memcpy(Save_Data.GPS_Buffer, GPS_BufferHead, GPS_BufferTail - GPS_BufferHead);      Save_Data.isGetData = true;clrGpsRxBuffer();    }  }}
void clrGpsRxBuffer(void){  memset(gpsRxBuffer, 0, gpsRxBufferLength);      //清空  ii = 0;}

这样编译上传后,我们就可以看见解析后的地理信息。是不是更加直观了?

这样我们就可以用双模定位模块获取更加精确定位数据,然后我们可以把这些数据再喂给一些GIS(地理信息系统)软件,或者可以利用python的一些库自己可视化数据。

在硬件方面,我们也可以增加电池和SD模块,让它长时间的保存定位信息,还可以添加GSM模块把数据通过移动网络传回服务器,这里我们就不深入了。


http://chatgpt.dhexx.cn/article/ZTx43O5C.shtml

相关文章

手机安装Linus系统

首先做准备工作&#xff0c;我们需要三个app&#xff0c;如下图所示&#xff1a; 分别是Anlinux(用于获取linux系统&#xff0c;这里我们选择Ubuntu系统),Termux(模拟Linux环境),旋风加速器(因为Termux的下载源在国外&#xff0c;所以我们需要使用其来连接国外站点) 首先我们打…

大神Linus

大神Linus 人物简介 林纳斯本纳第克特托瓦兹&#xff08;Linus Benedict Torvalds, 1969年~ &#xff09;&#xff0c;著名的电脑程序员、黑客。Linux内核的发明人及该计划的合作者。托瓦兹利用个人时间及器材创造出了这套当今全球最流行的操作系统&#xff08;作业系统&#…

Linus工作室 2021年 PB级存储方案

来自于加拿大Linux 工作室 本文章仅整理内容&#xff0c;另外还有一些本人的理解 实际上这已经是Linux PB计划第二代了&#xff0c;比第一代更加NB 原视频地址&#xff1a; https://www.bilibili.com/video/BV1nj411f7NL/?spm_id_from333.788.videocard.4 https://www.bilibil…

Linus安装JDK

一. 下载jdk1.8 链接&#xff1a;https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html, 选择Linus64位 下载完成后,将压缩包导入到linus opt文件夹下 tar -zxvf jdk-8u241-linux-x64.tar.gz 解压文件夹 ,然后修改环境变量 vim /etc/profile 按 “i…

Linux 30 周年,听 Linus 聊聊心路历程和开源洞见

Linus Torvalds 来了&#xff01; 1991 年&#xff0c;21 岁的赫尔辛基大学学生 Linus Torvalds&#xff08;以下简称 Linus&#xff09;创建了 Linux 内核。过去 30 年&#xff0c;Linux 从一个基于兴趣的小项目&#xff0c;发展成统治世界的操作系统内核&#xff0c;而 Linu…

为何 Linus 一个人就能写出Linux这么强的系统?

转自&#xff1a;默然 Coldwings&#xff08;知乎&#xff09; 链接&#xff1a;www.zhihu.com/question/63187737 他是谁&#xff0c;Linus&#xff01; 林纳斯・托瓦兹&#xff08;Linus Torvalds, 1969 年~&#xff09;&#xff0c;著名程序员&#xff0c;Linux 内核的发…

linus 指针 linux,怼天怼地怼空气的Linus喜欢怎样的工作方式?

Linus Torvalds的“暴脾气”是出了名的&#xff0c;看到令自己不爽的事情就会怼过去&#xff0c;比如&#xff1a; 他曾经说Intel提交的漏洞修复程序是彻底的垃圾&#xff01; 当别人说Git没用C开发的时候&#xff0c; 他反击说“C是一种可怕的语言” 他喷别人的Pull Request :…

跑步机上的精彩人生——Linus大神传奇

全面学python的时代&#xff0c;作为程序员你怎么看&#xff1f; https://edu.csdn.net/topic/python115?utm_sourcecsdn_bw 本文来自微信公众号&#xff1a;格友 在这样的软件时代里&#xff0c;越来越多的人工作时离不开电脑&#xff0c;于是便有了各种各样的操作电脑的方式…

Git源码(Linus 版本)详解

温馨提示&#xff1a;建议打开目录观看 Linus 发疯文学欣赏 &#x1f47e; Git 是 Linux 之父 Linus Torvalds 于2005年开发的用于帮助管理 Linux 内核开发的开源版本控制软件。 美好的一天从阅读 Linus 的发疯文学开始。 (1) Linus 教你学习 Git (2) Linus 评价 CVS (Concur…

linux定时器王贤才,Linux之父Linus Torvald评价C++

Linux之父:C一无是处 不适合LINUX内核开发 Linux之父Linus Torvalds曾经在三年前&#xff0c;因为微软的一位同学质疑Git用C语言开发&#xff0c;而将C痛批了一顿。当时&#xff0c;他是这样评论的&#xff1a; C正处在困境当中&#xff0c;它既无助于简化&#xff0c;以实际用…

好书推荐--Linux之父Linus的自传《Just for Fun》

这本书非常有趣&#xff0c;它让你不由感到&#xff0c;在这个浮躁的社会&#xff0c;兴趣爱好是多么的重要&#xff01;至少能让你收获快乐。巴菲特说过这样一段话&#xff1a;“没钱没人脉时&#xff0c;请逼自己做好这三件事。第一&#xff0c;找到自己的兴趣爱好&#xff1…

linus 用的linux版本,Linus Torvalds的重大消息

Linux创始人Linus Torvalds在内核邮件列表上宣布正式释出Linux Kernel 4.9&#xff0c;这个版本被称为时尚改进最大的版本&#xff0c;同时4.10合并窗口已经开启。但值得注意的是&#xff0c;为期两周的合并窗口预计将在圣诞节这天关闭&#xff0c;因为假期的原因Torvalds考虑缩…

Linus基础

1.使用whereis查找locate命令 使用which查找whereis命令 使用locate查找rm命令 2.使用find命令查找当前路径下的所有普通文件 使用find查找file1.txt,file2.txt,file3.txt 3.cut命令的使用 4.uniq新建uniq_data.txt 使用uniq命令输出的结果 使用uniqming输出值重复的行 使用…

Linus:我终于在 M2 芯片的 MacBook 上发布了 Linux 最新版本!

整理 | 彭慧中 责编 | 屠敏 出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09; 近日&#xff0c;Linus Torvalds&#xff08;以下简称“Linus”&#xff09;宣布Linux Kernel 5.19正式版终于可以和大家见面了。这一版本意义重大&#xff0c;虽然它比原计划晚了…

Linus系统的详细安装教程:

第一步 首先创建虚拟机 1.打开VMware,点击左上角新建虚拟机如下: 2.选择相关选项(也可以选自定义,自定义完成下一步即可)如下图: 3.选择“稍后安装操作系统(S)"如下图: 4.版本也可以选择其他的Red Hat版本(CentOS是Red Hat中的一个开放版本)如下图: 5.…

为何 Linus 一个人就能写出这么强的系统,国人却做不出来?

点上方蓝色“菜鸟学Python”&#xff0c;选“星标”公众号 重磅干货&#xff0c;第一时间送到转自&#xff1a;默然 Coldwings&#xff08;知乎&#xff09; www.zhihu.com/question/63187737 他是谁&#xff0c;Linus&#xff01; 林纳斯・托瓦兹&#xff08;Linus Torvalds,…

Linux之父:Linus

林纳斯本纳第克特托瓦兹&#xff08;Linus Benedict Torvalds&#xff09;&#xff0c;是Linux之父&#xff0c;是Linux内核的缔造者。 1991年&#xff0c;年仅22岁的芬兰程序员Linus Torvalds发布了自己独创的操作系统—Linux。他将代码公布在网上&#xff0c;爱好者们也贡献者…

关于 Linux 之父,你可能不知道的 7 件事

如果让你现在说出三个程序员的名字&#xff0c;Linus 很可能就在其中。作为世界上最著名的电脑程序员、黑客之一&#xff0c;Linus Benedict Torvalds 写出了 Linux 内核 1.0 版&#xff0c;发起了开源运动&#xff0c;开发了代码管理工具 Git。 这三个成就中的任意一个&#x…

润乾报表中API自定义数据集

报表的数据来源大部分来自数据库&#xff0c;正常情况润乾报表都能自动处理&#xff0c;但是也会有特殊的情况&#xff0c;例如通过中间件连接数据库而非直连&#xff1f;通过业务程序算出的数据传递给报表进行展现等等。因此需要用户自定义数据集&#xff0c;我们看一个例子。…

使用Java随机划分数据集为训练集和测试集

在做机器学习&#xff0c;推荐系统等等实验的过程中&#xff0c;我们难免会自己来手动划分数据集&#xff0c;一般都是用一些python开源库来划分&#xff0c;今天我们使用Java自己写代码来随机划分数据集。以下数据集的格式为user item rating ,如图&#xff1a; 下面为代码&am…