智工运维定位器之ublox

article/2025/8/14 17:55:14

一,概述

 

GNSS芯片选用了ublox的 UBX-M8030 系列,有3个型号:

可以到官网去下载相关资料,文档还挺齐的:
https://www.u-blox.com/zh/product/ubx-m8030-series#tab-product-selection
比较重要的几个文档有:

ReceiverDescrProtSpec芯片通讯协议配置相关,软件开发较关心
DataSheet不用说了吧
HardwareIntegrationManual硬件设计详解
PowerManagement_AppNote电源及低功耗
GNSS-Antennas_AppNote天线相关

把选型相关和我比较关心的一些特性列一下:
最多可并发接收 3 个 GNSS(GPS、伽利略、GLONASS、北斗)
定位精度2米
-148 dBm 到 -167 dBm 灵敏度
冷启动26秒定位时间,热启动只要1.5s
1个串口,默认9600,8n1,本项目只用这个通讯口,其它的USB, I2C, SPI不关心
尺寸封装:QFN, 5x5
支持低电压,支持低功耗模式(这个对我们很重要)

简单来说,如果硬件没问题,天线调试可以,那样芯片会自动每秒发送一次信息,如果已定位成功,就有位置信息了,软件只要解析报文就可以。状态机如下图,acquisition我们叫搜星,tracking就是跟踪。

 Ublox还专门提供了一个调试用的软件,叫u-center,官网可下载。安装到PC上,通过串口与芯片通讯,分析芯片发过来的位置信息报文,图文展示卫星等信息,也支持下发配置,非常方便。

二,硬件

先说明,本人软件工程师,硬件水平渣。如果之前没有研发过GPS类芯片的硬件工程师可能要好好把文档看懂才动手,尤其是天线部分,后面会专门分析该部分。芯片主体框图如下:

 我们项目中原理图如下(天线部分后面提供):

 2.1 电源


上图把几个重要的外围接口都列了出来,芯片有几个供电pin 脚,硬件要怎么供电取决于你的需求,上图的Main Supply实际上有两路电源输入,V_CORE, 和 V_DCDC,几个电源接口有着不同的功能。
V_BCKP,给RTC,RAM供电,用来保存星历,下次定位更快,功耗只有15uA
V_CORE, 搜星时功耗,只有GPS时 33.6 mA, GNSS 43.2 mA
V_DCDC_IN, 只有GPS时18.3 mA, GNSS 24.2mA
VDD_IO,通讯pin 脚供电

详细功能看官方文档,这里只截个图:

 2.2 低功耗

低功耗与性能是个矛盾关系,各人根据需求去配置,例如硬件上有以下做法可以省电:
主电源1.4v供电
使用晶振(Crystal)而不是TCXO
用UART and DDC接口通讯,而不是USB, SPI
不使用SQI Flash(ROM only version)
无源天线(性能很受影响)

在软件上芯片有两种工作模式,连续模式(Continuous Mode)和省电模式(Power Save Mode,PSM)。连续模式就是使用全部性能,全部通道去搜星,星历都下载OK后进入跟踪引擎,这时功耗会降低。

 如上图最开始阶段,芯片(acquisition engine)尽最大能力搜星,星历下载完成,得到初始位置信息后,芯片关闭acquisition engine进入跟踪状态。检测到新的卫星信号又重新启动acquisition engine,也就是上图的fix阶段。很明显,要省电最好是加长”Update Period”的时间,也就是说省电模式只在跟踪阶段。
省电模式又分两种模式:”Cyclic tracking” 和 “ON/OFF operation”,从下图可以看出,只有设置”Update Period”超过10s “ON/OFF operation”才有省电优势,这也会影响到性能,看用户怎么平衡了。

 要想进入低功耗模式,要满足以下条件:
不要使用USB接口
有RTC,或者使用"single crystal"模式
使用GPS-only 模式


芯片配置步骤:
1. disable Glonass, 只要GPS。 UBX-CFG-GNSS
2. UBX-CFG-PM2 或者 UBX-CFG-PMS,一般推荐使用Cyclic tracking
3. UBX-CFG-RXM, set the power mode to "1 - Power Save Mode"

 2.3 时钟

从前面系统框图可知,这个芯片有两路时钟输入,分别是TCXO(或晶振)和RTC时钟,参考框图如下:

主时钟是一定要有的,而且对搜星性能有影响,温漂要控制在范围内。可以根据需求,成本,性能分析是使用TCXO还是晶振,频率是26 MHz,” HardwareIntegrationManual”文档会有专门的分析,这个文档很细,把外围电路各种器件的参考物料都列了出来,买文档推荐的物料肯定没错了。
主时钟是供信号采集用的,RTC是用来备份和热保持,当芯片主电源意外掉电,芯片热启动时会用到,频率是32.768 kHz。芯片也支持单晶振(Single Crystal)模式,就是主晶振也可以作RTC用,这需要配置芯片。这样V_BCKP电源也会给主晶振供电,主电源掉的时候主晶振依然能工作。这么做能省物料成本,但是增加了功耗。

2.4 IO配置


UBX-M8030芯片有17个IO口,从PIO0到PIO16,都是由VDD_IO供电,而且电平也跟它一致。PIO0到PIO5可以连SQI Flash,SQI Flash的作用是升级芯片固件,保存配置,保存log,保留辅助定位信息。这几个pin脚也可以通过配置作为LDO输出的功能。我们项目没用SQI Flash,也没用LDO输出,所以都悬空了。

 三,天线

 天线部分我们硬件参考了” HardwareIntegrationManual”文档里面的最佳性能电路,如下图:

 我们的原理图:

 如上图所示,最左边BWGNSCNX16-6W是天线座,U11的MAX2659是一个LNA(Low Noise Amplifier,低噪声放大器)芯片,用来放大信号。U9的SAFEB1G57KE0F00R15是一个声表面波滤波器(SAW),用来滤波,特别是我们的项目中用到了lte cat.1芯片,怕信号会干扰。经过这些简单处理后信号被送到芯片,整个过程如下图:

 要求硬件把外围电路处理好,然后重点就是天线的调试了。Ublox有专门文档介绍天线相关知识(GNSS-Antennas_AppNote),建议先看看。其实如果硬件工程师射频相关经验不多的话,最好是找天线厂帮忙,我们就因为这个浪费了一,两星期的时间。GPS的信号很弱,-100dBm以上的,天线比2.4G,433M之类的天线要难搞,还是要请专业人士保险。本人这一块也薄弱,只提供几个建议:
天线分陶瓷天线和FPC天线,增益强度,指向,体积都不一样,看产品需求选用。
天线对PCB有要求,例如净空,铺地,阻抗之类的,最好先让射频工程师评估。
串口输出的报文要能看懂,u-center最好会使用,能了解和推算出信号强弱。
产品外壳也很重要,天线的位置会有关系
最好还是有专业人员参与

 四,u-center

u-center 软件的功能非常强大,我只使用了其中小部分功能,主界面如下:

 


上图左边部分用来查看串口输出数据流,配置界面等,这些界面都可以通过菜单栏的view子菜单打开。右边会把数据解析后的实时结果展示出来,包括当前搜到的星,信号强度,如果定位到的话会有位置,海拔,速度等信息。几个view的作用:
Text console 打印串口上报的报文,如上图左边部分。
Messages View 上报的报文通过NMEA协议解析出来,是字符格式,可以直接查看。下发配置报文一般用UBX协议,是二进制格式,而且有窗口显示要发送的报文内容。因为我下发的配置都是固定的,我一般在这里把要配置的内容测试OK,然后直接把二进制内容复制到代码去,省去组织报文的代码,特别是检验码是要计算出来的。
 

 

另外还有configuration view 和 statistic view用得多一点。建议调试时先把硬件调OK了再写功能代码。
 

五,软件

直接贴别人开源项目的代码,侵删:

ublox.h

/*Andrea ToscanoU-BLOX NEO M8M Parser
*/#ifndef UBLOX_H_INCLUDED
#define UBLOX_H_INCLUDED#include <Arduino.h>#include <stdint.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>class Ublox
{
public:class Tokeniser{public:Tokeniser(char* str, char token);bool next(char* out, int len);private:char* str;char token;};struct satellite{uint8_t prn;int16_t elevation;int16_t azimuth;uint8_t snr; //signal to noise ratio};struct _datetime{uint8_t day, month, year;uint8_t hours, minutes, seconds;uint16_t millis;bool valid; //1 = yes, 0 = no};enum _fixtype { FIX_TYPE_NONE, FIX_TYPE_GPS, FIX_TYPE_DIFF };enum _fix { FIX_NONE = 1, FIX_2D, FIX_3D };enum _op_mode { MODE_MANUAL, MODE_AUTOMATIC };bool encode(char c);float latitude, longitude, altitude, vert_speed;int latlng_age, alt_age;//these units are in hundredths//so a speed of 5260 means 52.60km/huint16_t speed, course, knots;int speed_age, course_age, knots_age;_fixtype fixtype; //0 = no fix, 1 = satellite only, 2 = differential fixint fixtype_age;_fix fix;int fix_age;float pdop, hdop, vdop; //positional, horizontal and vertical dilution of precisionint dop_age;int8_t sats_in_use;int8_t sats_in_view;satellite sats[12];int sats_age;_datetime datetime;int time_age, date_age;_op_mode op_mode;private:bool check_checksum();uint8_t parse_hex(char h);bool process_buf();char buf[120];uint8_t pos;void read_gga();void read_gsa();void read_gsv();void read_rmc();void read_vtg();};//extern Ublox gps;#endif // UBLOX_H_INCLUDED

ublox.c

#include "Ublox.h"Ublox::Tokeniser::Tokeniser(char* _str, char _token)
{str = _str;token = _token;
}bool Ublox::Tokeniser::next(char* out, int len)
{uint8_t count = 0;if(str[0] == 0)return false;while(true){if(str[count] == '\0'){out[count] = '\0';str = &str[count];return true;}if(str[count] == token){out[count] = '\0';count++;str = &str[count];return true;}if(count < len)out[count] = str[count];count++;}return false;
}bool Ublox::encode(char c)
{buf[pos] = c;pos++;if(c == '\n') //linefeed{bool ret = process_buf();memset(buf, '\0', 120);pos = 0;return ret;}if(pos >= 120) //avoid a buffer overrun{memset(buf, '\0', 120);pos = 0;}return false;
}bool Ublox::process_buf()
{if(!check_checksum()) //if checksum is bad{return false; //return}//otherwise, what sort of message is itif(strncmp(buf, "$GNGGA", 6) == 0){read_gga();}if(strncmp(buf, "$GNGSA", 6) == 0){read_gsa();}if(strncmp(buf, "$GPGSV", 6) == 0){read_gsv();}if(strncmp(buf, "$GNRMC", 6) == 0){read_rmc();}if(strncmp(buf, "$GNVTG", 6) == 0){read_vtg();}return true;
}// GNGGA 
void Ublox::read_gga()
{int counter = 0;char token[20];Tokeniser tok(buf, ',');while(tok.next(token, 20)){switch(counter){case 1: //time{float time = atof(token);int hms = int(time);datetime.millis = time - hms;datetime.seconds = fmod(hms, 100);hms /= 100;datetime.minutes = fmod(hms, 100);hms /= 100;datetime.hours = hms;time_age = millis();}break;case 2: //latitude{float llat = atof(token);int ilat = llat/100;double mins = fmod(llat, 100);latitude = ilat + (mins/60);}break;case 3: //north/south{if(token[0] == 'S')latitude = -latitude;}break;case 4: //longitude{float llong = atof(token);int ilat = llong/100;double mins = fmod(llong, 100);longitude = ilat + (mins/60);}break;case 5: //east/west{if(token[0] == 'W')longitude = -longitude;latlng_age = millis();}break;case 6:{fixtype = _fixtype(atoi(token));}break;case 7:{sats_in_use = atoi(token);}break;case 8:{hdop = atoi(token);}break;case 9:{float new_alt = atof(token);vert_speed = (new_alt - altitude)/((millis()-alt_age)/1000.0);altitude = atof(token);alt_age = millis();}break;}counter++;}
}void Ublox::read_gsa()
{int counter = 0;char token[20];Tokeniser tok(buf, ',');while(tok.next(token, 20)){switch(counter){case 1: //operating mode{if(token[0] == 'A')op_mode = MODE_AUTOMATIC;if(token[0] == 'M')op_mode = MODE_MANUAL;}break;case 2:{fix = _fix(atoi(token));fix_age = millis();}break;case 14:{pdop = atof(token);}break;case 15:{hdop = atof(token);}break;case 16:{vdop = atof(token);dop_age = millis();}break;}counter++;}
}void Ublox::read_gsv()
{char token[20];Tokeniser tok(buf, ',');tok.next(token, 20);tok.next(token, 20);tok.next(token, 20);int mn = atoi(token); //msg numbertok.next(token, 20);sats_in_view = atoi(token); //number of satsint8_t j = (mn-1) * 4;int8_t i;for(i = 0; i <= 3; i++){tok.next(token, 20);sats[j+i].prn = atoi(token);tok.next(token, 20);sats[j+i].elevation = atoi(token);tok.next(token, 20);sats[j+i].azimuth = atoi(token);tok.next(token, 20);sats[j+i].snr = atoi(token);}sats_age = millis();
}void Ublox::read_rmc()
{int counter = 0;char token[20];Tokeniser tok(buf, ',');while(tok.next(token, 20)){switch(counter){case 1: //time{float time = atof(token);int hms = int(time);datetime.millis = time - hms;datetime.seconds = fmod(hms, 100);hms /= 100;datetime.minutes = fmod(hms, 100);hms /= 100;datetime.hours = hms;time_age = millis();}break;case 2:{if(token[0] == 'A')datetime.valid = true;if(token[0] == 'V')datetime.valid = false;}break;/*case 3:{float llat = atof(token);int ilat = llat/100;double latmins = fmod(llat, 100);latitude = ilat + (latmins/60);}break;case 4:{if(token[0] == 'S')latitude = -latitude;}break;case 5:{float llong = atof(token);float ilat = llong/100;double lonmins = fmod(llong, 100);longitude = ilat + (lonmins/60);}break;case 6:{if(token[0] == 'W')longitude = -longitude;latlng_age = millis();}break;*/case 8:{course = atof(token);course_age = millis();}break;case 9:{uint32_t date = atoi(token);datetime.year = fmod(date, 100);date /= 100;datetime.month = fmod(date, 100);datetime.day = date / 100;date_age = millis();}break;}counter++;}
}void Ublox::read_vtg()
{int counter = 0;char token[20];Tokeniser tok(buf, ',');while(tok.next(token, 20)){switch(counter){case 1:{course = (atof(token)*100);course_age = millis();}break;case 5:{knots = (atof(token)*100);knots_age = millis();}break;case 7:{speed = (atof(token)*100);speed_age = millis();}break;}counter++;}
}bool Ublox::check_checksum()
{if (buf[strlen(buf)-5] == '*'){uint16_t sum = parse_hex(buf[strlen(buf)-4]) * 16;sum += parse_hex(buf[strlen(buf)-3]);for (uint8_t i=1; i < (strlen(buf)-5); i++)sum ^= buf[i];if (sum != 0)return false;return true;}return false;
}uint8_t Ublox::parse_hex(char c)
{if (c < '0')return 0;if (c <= '9')return c - '0';if (c < 'A')return 0;if (c <= 'F')return (c - 'A')+10;return 0;
}

代码是c++写的,单片机不好支持,我修改为c了。代码的使用较简单,GPS串口发过来的每一个字节都丢到encode函数去,如果检测到换行符'\n',会调用process_buf函数解析,解析后得到时间,经纬度等值。

end


---------------------
作者:歌维
来源:CSDN
原文:https://blog.csdn.net/gavinpeng/article/details/120676552
版权声明:本文为作者原创文章,转载请附上博文链接!
内容解析By:CSDN,CNBLOG博客文章一键转载插件


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

相关文章

如何配置ublox ZED-F9P 高精度模块+Ntrip DTU 网络电台(连接千寻/CORS/自建站)实现网络RTK定位

格林恩德F9P-RTK模块&#xff0c;集成高精度板卡(ZED-F9P)可同时接收GPS,北斗&#xff0c;GALILEO,GLONASS 卫星系统的L1,L2频点&#xff0c;结合高精度天线一体化设计&#xff0c;体积小&#xff0c;重量轻&#xff0c;只需外部5V供电&#xff0c;外接配合NTRIP DTU 网络差分电…

UBLOX F9P 高精度GNSS定位板卡的基准站,流动站设置与简单的短基线单主机双模块RTK设置

1.基础配置 如图&#xff0c;笔者拿到的是基于USB输出的F9P模块而非平常的串口输入输出模块&#xff0c;于是本次的设置均会基于USB的设置来进行。 首先拿到模块后&#xff0c;接上一个较好的天线&#xff0c;并接上电脑&#xff08;注意要选择与模块和天线两端射频连接器对应…

UBLOX配置/GPS配置设置/u-center使用

对u-blox的GPS接收机设置可以查看文档&#xff0c;文档比较长&#xff0c;刚开始看完全没有头绪&#xff0c;可以使用u-center对b-blox进行设置。本文先描述使用u-center的设置方法&#xff0c;随后补充一些配置报文的解读。 一、u-center的使用 选择串口 然后选择vie->Text…

力软快速开发框架最新版说明及源码(多语言版本)

废话少说&#xff0c;直接上图 说明文档截图 新建数据库&#xff1a; 打开sqlserver脚本&#xff0c;运行 打开源码&#xff0c;配置数据库连接&#xff0c;2个database.config,一个数据库配置 打开redis 运行调试 登录帐号&#xff1a;system&#xff0c;密码0000进入界面

强大asp.net智能开发工具,力软快速开发平台

力软是一家专业从事软件研发、销售于一体的技术服务型公司。公司本着诚信为根本、竞争为导向、 创新为动力&#xff0c;服务为基础的经营理念&#xff0c;为用户提供定制化的技术服务。 力软是专业的平台及管理软件提供商&#xff0c;自成立至今一直致力于自主软件产品平台的研…

力软:web主流工作流引擎的领导者

目前工作流引擎技术在企业的信息化过程中扮演了越来越重要的角色&#xff0c;许多终端客户在对应用系统进行选型时都会对工作流做特别的关注。 事实上工作流的概念已经在软件行业里深入人心&#xff0c;各大软件公司也开始纷纷布局&#xff0c;可是在不同技术平台下的工作流引…

力软敏捷框架开发工作流引擎设计

1、前言 提到工作流很多人都会想到OA&#xff0c;AO就是典型的工作流应用&#xff0c;但是工作流并不仅仅局限于OA&#xff0c;工作流应用该算是基础框架软件&#xff0c;主要用于流程的重组和优化&#xff0c;它有广阔的应用领域。在C#下我们自己研发工作流引擎等&#xff0c;…

敏捷开发框架有哪些?

1.jeecg-boot 2.力软敏捷开发框架 3.JNPF快速开发平台 4.pigx

力软敏捷开发框架7.0小更新,新增和完善应用基本功

此版本是力软敏捷开发框架7.0版本的最新版&#xff0c;新增和完善应用基本功能&#xff08;Redis消息、甘特图、表格控件、代码生成器、数据查询、套打&#xff09;&#xff0c;进一步加强代码生成器&#xff0c;支持方案保存极大提升开发的便利&#xff0c;PC端和移动端做了大…

力软:九年沉淀,从呱呱坠地到风华少

都说十年磨一剑&#xff0c;九年&#xff0c;想想也不短了&#xff0c;力软这把剑也比当初锋利了许多&#xff0c;今天我想顺着锋芒&#xff0c;带大家来了解一下这个备受呵护的孩子。 记得当初&#xff0c;三个人&#xff0c;一件工作室&#xff0c;怀抱着对开发行业的热情投入…

力软敏捷开发框架工作流实现技术

工作流管理联盟&#xff08;WFMC&#xff09;提出了一个工作流参考模型&#xff0c;约定了工作流系统的体系结构、应用接口及特性&#xff0c;主要目的是为了实现工作流技术的标准化和开放性。下面简要介绍系统中的各个部分&#xff0c;并对参考模型中的五类接口进行描述。 1&a…

力软快速开发平台,强大工作流引擎,助推企业管理升级

在信息时代的今天&#xff0c;企业管理中的五要素&#xff1a;人、财、物、信息、时间在企业经营中的重要性在发生剧烈演变&#xff0c;人的地位已经与日俱升&#xff0c;管好人、用好人、育好人&#xff0c;成为企事业单位的管理中心&#xff0c;信息化已经成为提升企业竞争力…

.NET CORE敏捷开发框架,企业信息化自主化解决方案

什么是力软.NET CORE敏捷开发框架 力软.NET CORE敏捷开发框架是一个高效率、高颜值、易上手的跨平台全开源快速开发平台。 高效率 框架内置企业信息化系统中常用的基础功能组件和高效的可视化开发工具&#xff0c;包括&#xff1a;向导式智能开发组件、即时通讯组件、APP开发…

力软敏捷开发框架-轻量化app一键快速开发

APP怎么快速开发&#xff1f;2018年&#xff0c;力软敏捷开发框架的APP在线制作平台已经逐步成熟。你不需要任何的编程技术&#xff0c;自己就可以通过力软敏捷开发框架上面的APP应用&#xff0c;拼图式自己快速搭建出一个手机互联网APP。 在整体框架都已经搭建好了&#xff…

力软快速开发平台建设心得

做软件开发&#xff0c;无外乎一个快字。 这就像功夫&#xff0c;天下武功唯快不破&#xff0c;谁出招快往往就有更多的胜算&#xff0c;但是现在&#xff0c;好像又有点不对头了。 为什么&#xff1f; 因为现在&#xff0c;仅仅是快已经不能解决问题了&#xff0c;很多软件…

力软

力软 发布时不包含 看csproj文件里面 none 封装 登录login admindefault _Admin.cshtml 默认加载js lr-base.js lr-tabs.js lr-admin.js 客户端语言包加载(菜单,tab条) tab窗口操作方法 拦截器 登陆验证 防伪验证 var request = filterContext.HttpCont…

力软敏捷开发框架,快速搭建企业级应用系统

力软敏捷开发框架是基于.net平台研发出的一套采用面向构件技术实现企业级应用开发、配置、运行集成一体的综合技术平台。平台可以开发企业整个应用软件体系&#xff0c;并为其提供一个组件化、低代码、可视化的软件开发模式。 框架作为企业级研发平台&#xff0c;为软件开发者提…

重磅:力软(JAVA)开发平台将于7月20日正式上线

力软&#xff08;JAVA&#xff09;开发平台是一款智能化可扩展组件式Web应用开发与运行平台。 基于浏览器的集成开发环境&#xff0c;采用可视化的设计模式&#xff0c;支持控件的拖拽操作&#xff0c;能轻松完成前后台应用开发&#xff1b;高效、稳定和可扩展的特点&#xff…

力软快速开发框架的建设与介绍

大家都知道现在大规模金融信息系统的业务复杂性高&#xff0c;同时对系统的性能、可用性、可靠性和安全性都有非常高的要求&#xff0c;因此&#xff0c;要进行规范的金融信息系统的建设&#xff0c;一套成熟的快速开发框架的支持是必吧可少的。力软软件的构件化快速开发框架面…

力软敏捷开发框架源码7.0.6旗舰版 JNPF开发平台3.4.5 企业版 旗舰版

软件架构 1、控制层 Spring Framework4.2 2、安全框架&#xff1a;Apache Shiro1.3 3、视图框架&#xff1a;SpringMVC4.2 4、持久层框架&#xff1a;Mybaits3.3 5、数据库连接池&#xff1a;Druid1.0 6、页面交互&#xff1a;vue2.0 7、前后端分离&#xff1a;Swagger2 8、定时…