C++读取GPS并解析 NMEA 数据
完整代码在我的Github地址https://github.com/dockermyself/gps_read
GGA
$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47
- $GPGGA:数据的类型标识符。
- 123519:UTC 时间,格式为时分秒(hhmmss)。
- 4807.038:纬度,格式为度分(ddmm.mmm)。
- N:纬度方向,N 表示北纬。
- 01131.000:经度,格式为度分(dddmm.mmm)。
- E:经度方向,E 表示东经。
- 1:GPS 修正,0 表示无效定位,1 表示有效定位。
- 08:用于定位的卫星数量。
- 0.9:HDOP(Horizontal Dilution of Precision)水平精度因子。
- 545.4:海拔高度,单位为米。
- M:海拔高度单位,M 表示米。
- 46.9:大地水准面与海平面的高度差,单位为米。
- M:高度差单位,M 表示米。
- *47:校验和,用于验证数据的完整性。
RMC
$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A
$GPRMC:数据的类型标识符。
-
123519:UTC 时间,格式为时分秒(hhmmss)。 A:数据状态,A 表示有效定位,V 表示无效定位。
-
4807.038:纬度,格式为度分(ddmm.mmm)。 N:纬度方向,N 表示北纬。
-
01131.000:经度,格式为度分(dddmm.mmm)。 E:经度方向,E 表示东经。
-
022.4:地面速度,单位为节。
-
084.4:地面航向,以真北方向为基准,以度为单位。 230394:日期,格式为日月年(ddmmyy)。
-
003.1:磁偏角,以度为单位。 W:磁偏角方向,W 表示西偏。
-
*6A:校验和,用于验证数据的完整性。
GGA 报文提供了有关定位和修正数据的信息,而 RMC 报文则包含了推荐的最小定位信息,包括地面速度和航向。通过解析这些报文,可以获取准确的 GPS 位置信息,并用于各种应用程序,如船舶导航、车辆追踪和户外活动。
代码解析
这里定义了一个结构体 LLA,用于存储解析后的 GPS 数据。它包括了 GPS 数据的代码、时间戳、纬度、经度、海拔高度和状态。
code:用于标识 GPS 数据类型的字符串。 timestamp:时间戳,表示获取数据的时间。 lat:纬度。 lon:经度。 alt:海拔高度。 status:数据状态,默认值为 -1,表示无效数据。
// GGA和RMC的数据结构
struct LLA
{
char code[10];
double timestamp;
double lat;
double lon;
double alt;
int status;
LLA() : status(-1) {}
};
这里定义了 GPSReader 类,它包含了 GPS 设备的串口通信、运行状态、数据缓存以及一些操作方法。
- SerialPort _serial:用于串口通信的对象。
- std::atomic _running:用于标识读取线程是否运行的原子布尔型变量。
- std::atomic _empty:用于标识数据缓存是否为空的原子布尔型变量。
- std::atomic _data:存储 GPS 数据的原子 LLA 结构体对象。
class GPSReader
{
SerialPort _serial;
std::atomic<bool> _running = {false};
std::atomic<bool> _empty = {true};
std::atomic<LLA> _data = {LLA()};
public:
GPSReader(std::string port, int baudrate) : _serial(port, baudrate) {}
void EnableReadThread();
void DisableReadThread();
bool getData(LLA &lla);
~GPSReader();
private:
// 私有方法和成员变量
};
- find_dollar 和 find_star 方法用于在 NMEA 数据中定位 $ 和 * 字符的位置。
- check 方法用于计算 NMEA 数据的校验和。
- ParseGGA 和 ParseRMC 方法用于解析 GGA 和 RMC 类型的 NMEA 数据。
private:
int find_dollar(const char *buf, int start, int end, std::string &head_code, int code_max_size = 10);
int find_star(const char *buf, int start, int end);
int check(const char *buf, int len);
bool check(const char *buf, int *pack_start, int pack_end, std::string &head_code, int max_code_size = 10);
void print_bytes(const char *buf, int len);
bool ParseGGA(const std::string buf, LLA &lla);
bool ParseRMC(const std::string buf, LLA &lla);
void SetLLA(LLA &lla, double _timestamp, double _lat, double _lon, double _alt, int _status, const std::string &_code);
轨迹绘制

实验设备
RK3588嵌入式板子+G60 GPS模块

1632

被折叠的 条评论
为什么被折叠?



