$GPRMC解析
$GPRMC解析
帧头 | UTC时间 | 状态 | 纬度 | 北纬/南纬 | 经度 | 东经/西经 | 速度 |
$GPRMC | hhmmss.sss | A/V | ddmm.mmmm | N/S | dddmm.mmmm | E/W | 节 |
方位角 | UTC日期 | 磁偏角 | 磁偏角方向 | 模式 | 校验 | 回车换行 |
度 | ddmmyy | 000 - 180 | E/W | A/D/E/N | *hh | CR+LF |
格 式:
$GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>*hh<CR><LF>
$GPRMC,024813.640,A,3158.4608,N,11848.3737,E,10.05,324.27,150706,,,A*50
说 明:
字段 0:$GPRMC,语句ID,表明该语句为Recommended Minimum Specific GPS/TRANSIT Data(RMC)推荐最小定位信息
字段 1:UTC时间,hhmmss.sss格式
字段 2:状态,A=定位,V=未定位
字段 3:纬度ddmm.mmmm,度分格式(前导位数不足则补0)
字段 4:纬度N(北纬)或S(南纬)
字段 5:经度dddmm.mmmm,度分格式(前导位数不足则补0)
字段 6:经度E(东经)或W(西经)
字段 7:速度,节,Knots(一节也是1.852千米/小时)
字段 8:方位角,度(二维方向指向,相当于二维罗盘)
字段 9:UTC日期,DDMMYY格式
字段10:磁偏角,(000 - 180)度(前导位数不足则补0)
字段11:磁偏角方向,E=东,W=西
字段12:模式,A=自动,D=差分,E=估测,N=数据无效(3.0协议内容)
字段13:校验值
对应的程序代码如下:
package cc.oyz.gps; import lombok.Data; import org.apache.log4j.Logger; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.TimeZone; /** * @description: * @author: libin.hao * @time: 2021/3/31 9:43 */ @Data public class GPRMC extends GpsInfoRecord { private static Logger log = Logger.getLogger(GPRMC.class); private static SimpleDateFormat dateFormat = new SimpleDateFormat("ddMMyy HHmmss.SSS"); static { // set the timezone for analysis of dates on UTC dateFormat.setCalendar(Calendar.getInstance(TimeZone.getTimeZone("UTC"))); } private boolean isValid; private double latitude; private double longitude; private Date readingDate; protected GPRMC(String[] fields) { super(fields); try { this.readingDate = dateFormat.parse(fields[9] + " " + fields[1]); } catch (ParseException e) { log.error("Couldn't parse reading date", e); log.debug("Will assume _now_ as reading date"); this.readingDate = new Date(); } this.isValid = fields[2].equals("A"); if(isValid){ String rawLat = fields[3]; String rawLong = fields[5]; if(rawLat.length() > 0 && rawLong.length() > 0){ int degrees = Integer.parseInt(rawLat.substring(0, 2)); double minutes = Double.parseDouble(rawLat.substring(2)); this.latitude = degrees + minutes / 60; if (fields[4].equals("S")) { this.latitude *= -1; } degrees = Integer.parseInt(rawLong.substring(0, 3)); minutes = Double.parseDouble(rawLong.substring(3)); this.longitude = degrees + minutes / 60; if (fields[6].equals("W")) { this.longitude *= -1; } } } } @Override public String toString() { return "GPRMC{" + "isValid=" + isValid + ", latitude=" + latitude + ", longitude=" + longitude + ", readingDate=" + readingDate + '}'; } }
package cc.oyz.gps; /** * @description: gps信息记录 * @author: libin.hao * @time: 2021/3/31 9:31 */ public class GpsInfoRecord extends GpsEvent{ protected String[] fields; public static GpsInfoRecord createRecord(String inputLine) throws InvalidInputException { if (inputLine.length() == 0) { throw new InvalidInputException("输入行为空"); } if (inputLine.charAt(0) != '$') { throw new InvalidInputException("Record doesn't start with $"); } int checksumPos = inputLine.indexOf('*'); if (checksumPos != -1) { /* * FIXME has checksum, let's check it.... but, for now, let's just * strip it */ inputLine = inputLine.substring(0, checksumPos); } String[] fields = inputLine.substring(1).split(","); if (fields[0].equals("GPRMC")) { return new GPRMC(fields); } else { return new UnknownGpsInfoRecord(fields); } } public GpsInfoRecord(String[] fields) { this.fields = fields; } public int getFieldsCount() { return fields.length; } public String getField(int index) { return fields[index]; } public String toString() { return fields[0] + " (from GpsEvent)"; } }
package cc.oyz.gps; /** * @description: gps事件监听 * @author: libin.hao * @time: 2021/3/31 9:29 */ public abstract class GpsEvent { }
package cc.oyz.test.gps; import cc.oyz.gps.GPRMC; import cc.oyz.gps.GpsInfoRecord; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import java.io.BufferedReader; import java.io.FileReader; import java.text.SimpleDateFormat; /** * @description: * @author: libin.hao * @time: 2021/3/31 9:52 */ // 让 JUnit 运行 Spring 的测试环境, 获得 Spring 环境的上下文的支持 @RunWith(SpringJUnit4ClassRunner.class) // 获取启动类,加载配置,确定装载 Spring 程序的装载方法,它回去寻找 主配置启动类(被 @SpringBootApplication 注解的) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class GpsTest { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); //解析单体数据 @Test public void gpsStr(){ String str = "$GPRMC,064159.000,A,4002.3959,N,11619.5986,E,5.93,189.9,310321,,*34"; try { GpsInfoRecord record = GpsInfoRecord.createRecord(str); if(record instanceof GPRMC){ GPRMC gprmc = (GPRMC) record; String formatDate = simpleDateFormat.format(gprmc.getReadingDate()); System.out.println("格式化时间:" + formatDate);
System.out.println(gprmc);} }catch (Exception e){ System.err.println("错误日志:" + e.getMessage()); } } }
打印结果:
格式化时间:2021-03-31 02:41:59 GPRMC{isValid=true, latitude=40.03993166666667, longitude=116.32664333333334, readingDate=Wed Mar 31 14:41:59 CST 2021}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析