尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
【ESP32S3 + ATGM332D GPS模块实战:从NMEA解析到本地速度计算】
【ESP32S3 ATGM332D GPS模块实战从NMEA解析到本地速度计算】项目概述一、硬件准备1.1 核心部件1.2 硬件连接二、软件配置2.1 PlatformIO环境配置2.2 核心库介绍三、代码实现3.1 完整代码3.2 关键技术解析3.2.1 NMEA数据解析3.2.2 本地墨卡托投影ENU坐标系3.2.3 速度与航向计算四、测试结果4.1 输出示例4.2 数据对比分析4.3 关键指标五、常见问题排查5.1 定位无效5.2 速度为05.3 航向跳变六、总结项目概述本文详细介绍如何使用ESP32通过硬件串口读取ATGM332D GPS模块数据使用TinyGPSPlus库解析NMEA语句并通过本地墨卡托投影ENU坐标系计算真实速度和航向。源码地址https://download.csdn.net/download/VOR234/93024101一、硬件准备先采用GnssToolKit3配置GPS使用模式为航海模式更新速率为10Hz配置波特率为9600查看原始NEMA数据查看收星情况1.1 核心部件部件型号说明主控板ESP32-S3开发板GPS模块ATGM332D支持GPS/北斗双模定位天线GPS有源天线SMA接口1.2 硬件连接ATGM332D模块 ESP32-S3 TX ---------- GPIO17 (UART1_RX) RX ---------- GPIO18 (UART1_TX) VCC ---------- 3.3V GND ---------- GND注意事项ATGM332D默认波特率为9600使用硬件串口Serial1避免占用调试串口GPS模块需外接有源天线并放置在开阔处二、软件配置2.1 PlatformIO环境配置在platformio.ini中添加依赖库[env:freenove_esp32_s3_wroom] platform espressif32 board freenove_esp32_s3_wroom framework arduino monitor_speed 115200 upload_speed 921600 lib_deps mikalhart/TinyGPSPlus^1.0.3 ; GPS NMEA解析库2.2 核心库介绍TinyGPSPlus是一个轻量级、高效的NMEA解析库特点支持所有标准NMEA语句自动解析经纬度、时间、速度、航向等信息内存占用小适合嵌入式设备三、代码实现3.1 完整代码#includeArduino.h#includeTinyGPSPlus.h#includemath.h// GPS模块配置#defineGPS_UARTSerial1// 使用硬件串口1#defineGPS_BAUD_RATE9600// ATGM332D默认波特率#defineGPS_TX_PIN18// UART1_TX#defineGPS_RX_PIN17// UART1_RX#definePRINT_INTERVAL_MS500// 2Hz输出频率// TinyGPSPlus对象TinyGPSPlus gps;// 参考点初始位置作为本地坐标系原点doublerefLat0.0;doublerefLng0.0;boolrefSetfalse;// 上一时刻的位置和时间doublelastEast0.0;doublelastNorth0.0;unsignedlonglastTimeMs0;// 计算得到的速度和航向floatcalcSpeed0.0;floatcalcHeading0.0;// 将经纬度转换为本地ENU坐标voidlatLngToENU(doublelat,doublelng,doublerefLat,doublerefLng,doubleeast,doublenorth);voidsetup(){Serial.begin(115200);delay(500);Serial.println(ATGM332D GPS模块测试 - 本地墨卡托投影计算);// 初始化GPS串口GPS_UART.begin(GPS_BAUD_RATE,SERIAL_8N1,GPS_RX_PIN,GPS_TX_PIN);delay(1000);Serial.printf(GPS UART: Serial1, TX%d, RX%d, Baud%d\n,GPS_TX_PIN,GPS_RX_PIN,GPS_BAUD_RATE);Serial.printf(输出频率: %d Hz\n,1000/PRINT_INTERVAL_MS);Serial.println();}voidloop(){// 持续读取并解析GPS数据while(GPS_UART.available()0){gps.encode(GPS_UART.read());}// 定时输出2HzstaticunsignedlonglastPrintTime0;if(millis()-lastPrintTimePRINT_INTERVAL_MS){lastPrintTimemillis();Serial.println();if(gps.location.isValid()){doublelatgps.location.lat();doublelnggps.location.lng();// 设置参考点if(!refSet){refLatlat;refLnglng;refSettrue;Serial.println([INFO] 参考点已设置);}// 转换为ENU坐标doubleeast,north;latLngToENU(lat,lng,refLat,refLng,east,north);// 计算速度和航向unsignedlongcurrentTimeMsmillis();if(lastTimeMs0refSet){doubledt(currentTimeMs-lastTimeMs)/1000.0;if(dt0.01){doubledxeast-lastEast;doubledynorth-lastNorth;// 速度: m/s - km/hcalcSpeedsqrt(dx*dxdy*dy)/dt*3.6;// 航向: 弧度转角度0-360度calcHeadingatan2(dx,dy)*180.0/M_PI;if(calcHeading0)calcHeading360.0;}}// 更新状态lastEasteast;lastNorthnorth;lastTimeMscurrentTimeMs;// 输出数据Serial.println(定位状态: 有效);if(gps.time.isValid()){Serial.printf(UTC时间: %02d:%02d:%06.3f\n,gps.time.hour(),gps.time.minute(),gps.time.second()gps.time.centisecond()/100.0);}if(gps.date.isValid()){Serial.printf(日期: %04d-%02d-%02d\n,gps.date.year(),gps.date.month(),gps.date.day());}Serial.printf(纬度: %.6f°\n,lat);Serial.printf(经度: %.6f°\n,lng);Serial.printf(东向偏移: %.3f m\n,east);Serial.printf(北向偏移: %.3f m\n,north);Serial.printf(计算航速: %.6f km/h\n,calcSpeed);Serial.printf(计算航向: %.6f°\n,calcHeading);Serial.printf(原始航速: %.6f km/h\n,gps.speed.kmph());Serial.printf(原始航向: %.6f°\n,gps.course.deg());Serial.printf(卫星数量: %d\n,gps.satellites.value());if(gps.hdop.isValid()){Serial.printf(HDOP: %.2f\n,gps.hdop.hdop());}if(gps.altitude.isValid()){Serial.printf(海拔高度: %.2f m\n,gps.altitude.meters());}}else{Serial.println(定位状态: 无效);Serial.println(请将天线放置在开阔地带...);Serial.printf(已处理字符数: %lu\n,gps.charsProcessed());}Serial.println();Serial.println();}if(gps.charsProcessed()10){Serial.println(等待GPS数据...);delay(500);}}// 经纬度转ENU坐标voidlatLngToENU(doublelat,doublelng,doublerefLat,doublerefLng,doubleeast,doublenorth){constdoubleR6378137.0;// 地球半径(米)doublelatRadlat*M_PI/180.0;doublelngRadlng*M_PI/180.0;doublerefLatRadrefLat*M_PI/180.0;doublerefLngRadrefLng*M_PI/180.0;doublecosLatcos(refLatRad);eastR*(lngRad-refLngRad)*cosLat;northR*(latRad-refLatRad);}3.2 关键技术解析3.2.1 NMEA数据解析TinyGPSPlus通过gps.encode()方法逐字符解析NMEA数据流while(GPS_UART.available()0){gps.encode(GPS_UART.read());}解析后的关键数据gps.location.lat()- 纬度十进制度gps.location.lng()- 经度十进制度gps.speed.kmph()- 对地速度km/hgps.course.deg()- 航向角度度3.2.2 本地墨卡托投影ENU坐标系原理将地球表面近似为平面以首次定位点为原点建立东-北-天坐标系。核心公式eastR*(lng-refLng)*cos(refLat)northR*(lat-refLat)其中R 地球半径6378137米refLat,refLng 参考点经纬度east,north 相对于参考点的东向、北向偏移米3.2.3 速度与航向计算// 速度 位移 / 时间calcSpeedsqrt(dx*dxdy*dy)/dt*3.6;// 航向 arctan2(东向位移, 北向位移)calcHeadingatan2(dx,dy)*180.0/M_PI;说明速度单位转换m/s × 3.6 km/h航向范围0°正北→ 90°正东→ 180°正南→ 270°正西四、测试结果串口接收数据4.1 输出示例 定位状态: 有效 UTC时间: 13:01:11.600 日期: 2026-06-24 纬度: 38.869444° 经度: 121.532086° 东向偏移: -1.430 m 北向偏移: 2.727 m 计算航速: 3.079846 km/h 计算航向: 317.520691° 原始航速: 2.277960 km/h 原始航向: 323.150000° 卫星数量: 21 HDOP: 0.80 海拔高度: 82.00 m 4.2 数据对比分析参数原始GPS数据计算值ENU说明航速2.28 km/h3.08 km/h计算值更接近实际运动状态航向323.15°317.52°计算值基于实际位移方向4.3 关键指标定位精度水平精度优于1米HDOP 1.0卫星数量21颗GPS北斗双模更新频率约10Hz模块输出计算频率2Hz程序设定五、常见问题排查5.1 定位无效现象定位状态: 无效排查步骤检查天线连接是否牢固确保天线在室外开阔处等待至少30秒冷启动时间检查串口波特率是否正确ATGM332D默认96005.2 速度为0现象计算航速: 0.00 km/h排查步骤检查是否有连续的位置变化确认参考点已设置首次定位后检查时间差计算是否正确5.3 航向跳变现象航向角度突变原因GPS定位存在微小抖动低速运动时位移量小噪声影响大解决方案增加滤波算法如卡尔曼滤波对连续多个采样点进行平滑处理六、总结本文实现了从GPS数据采集到速度航向计算的完整流程硬件层面使用ESP32硬件串口与ATGM332D模块通信数据解析利用TinyGPSPlus库高效解析NMEA语句坐标转换通过本地墨卡托投影建立ENU坐标系速度计算基于位移差分计算真实运动参数该方案适用于无人机、机器人、车辆等需要实时定位和运动状态监测的应用场景。参考资料TinyGPSPlus官方文档ATGM332D模块手册NMEA-0183协议标准
RELATED

相关推荐

最近,架构的招聘市场已经疯掉了。。。

最近,架构的招聘市场已经疯掉了。。。

AI Coding,问世不到3年,职场已经天翻地覆! 感受到最近的招聘变化了吗?尤其是大厂的招聘动作:以前还分前端、后端、架构师……现在岗位表上只写四个字:Agent工程师! 为什么会有如此变化&#x…

📅 2026/9/20 14:32:35
早期停止聚合:用并行短任务加速统计推断与机器学习计算

早期停止聚合:用并行短任务加速统计推断与机器学习计算

1. 项目概述:当“提前下班”遇上统计推断在统计建模和机器学习的世界里,我们常常面临一个经典困境:计算成本与推断精度之间的拉锯战。无论是运行一个复杂的贝叶斯马尔可夫链蒙特卡洛模拟,还是执行一个需要大量重采样的频率派自助法…

📅 2026/9/18 13:39:05
Burp Suite与安卓模拟器抓包实战:解密HTTPS与微信小程序网络分析

Burp Suite与安卓模拟器抓包实战:解密HTTPS与微信小程序网络分析

1. 项目概述:为什么需要抓包模拟器?在移动应用和微信小程序的开发、测试乃至安全评估过程中,一个核心的痛点就是:我们如何像在浏览器里按F12一样,清晰地看到手机里每一个APP、每一个小程序发出的网络请求和接收的响应&…

📅 2026/9/19 10:25:05
MORE NEWS

更多资讯

📰

使用 Rube MCP 自动化 Anonyflow 操作:awesome-claude-skills 中 anonyflow-automation 技能实战指南

AI 技能AI 插件人工智能工作流自动化 【免费下载链接】awesome-claude-skills A curated list of awesome Claude Skills, resources, and tools for customizing Claude AI workflows 项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-claude-skills 点击…

📰

audio.cpp流式推理内幕:47ms首包延迟背后的持久会话与图缓存复用机制

audio.cpp流式推理内幕:47ms首包延迟背后的持久会话与图缓存复用机制 【免费下载链接】audio.cpp An all-in-one, pure C inference engine for audio models, powered by ggml. Supports TTS, STT, VAD, voice conversion, music generation, and more, with highl…

📰

GPTs 仓库深度拆解:Customer Service GPT 企业客服提示词全解析与落地复刻指南

提示工程 【免费下载链接】GPTs leaked prompts of GPTs 项目地址: https://gitcode.com/GitHub_Trending/gp/GPTs 点击查看 免费下载 本文以开源仓库 GPTs 中泄漏的 Customer Service GPT 提示词(由 Daniel J Patterson 构建)为绝对核心&am…

📰

ArcGIS Pro 用户请收下:这个免费插件,帮你一键加载中文底图和省市区县边界、世界地图集

用 ArcGIS Pro 的朋友,是不是都经历过这些崩溃瞬间: 想加载高德、天地图这类中文底图,得自己去翻瓦片地址、手动配 XYZ、改坐标系、填 token——折腾大半天,地图还是一片空白; 天地图 WMTS 的 tk 到底加在哪&#xff…

📰

反序输出题详解:从EOF到数组遍历的入门必修课

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

Codex-X 结构化长文起草模板解析:把零散材料组织成重点明确、论证连贯的完整初稿

桌面应用开发者工具AI 应用 【免费下载链接】Codex-X OpenAI Codex 桌面端/CLI 的可视化管理工具,具有Provider/API 切换、会话同步、提示词注入、Skills/MCP 管理、TOML 配置可视化的跨平台工具。 项目地址: https://gitcode.com/GitHub_Trending/co/Co…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬