IoT-For-Beginners 定位跟踪实战:用 CounterFit 虚拟 GPS 传感器读取 UART 位置数据
【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners
本文是 IoT-For-Beginners 课程 Transportation(运输)项目第 1 课「Location tracking(定位跟踪)」中虚拟设备分支的完整实战指南:基于 CounterFit 模拟一个通过 UART 串口输出的 GPS 传感器,用 Python 编写虚拟 IoT 设备程序读取原始 NMEA 数据,并掌握 Lat/Lon、NMEA、GPX 三种数据注入方式。读完并完成实操后,你将能在没有真实硬件的情况下搭建完整的 GPS 读取链路,为后续解码位置数据、构建车辆跟踪应用打下基础。
背景:虚拟 GPS 传感器如何模拟真实硬件
在本课中,你将给虚拟 IoT 设备(virtual IoT device)添加一个 GPS 传感器并读取它的值。虚拟设备使用的 GPS 传感器是一个模拟器件,通过 UART(通用异步收发传输器)以一个串口(serial port)对外提供数据。
真实 GPS 传感器内部有一根天线,用于接收 GPS 卫星的无线电波,并将 GPS 信号转换成 GPS 数据。虚拟版本通过以下三种方式模拟这一行为:
- 设置纬度和经度(Lat/Lon):直接指定一个位置,可同时指定参与定位的卫星数量;
- 发送原始 NMEA 语句(NMEA sentences):手动填入 NMEA 0183 标准报文,由虚拟传感器逐条发出;
- 上传 GPX 文件(GPX file):GPX 文件包含一条轨迹上的多个 GPS 位置点,虚拟传感器会按每秒 1 个的节奏依次返回每个位置。
注:NMEA 语句的具体含义(语句结构、GGA 定位报文、度分格式等)会在本课后续内容中专门讲解,对应课程主文档见 Location tracking 课程 README,英文原版本课本文档为 virtual-device-gps-sensor.md。
任务一:在 CounterFit 中添加 GPS 传感器
要使用虚拟 GPS 传感器,需要先把它添加到 CounterFit 应用中。
前置条件:Python 项目与 CounterFit 包
如果尚未完成虚拟设备环境搭建,可先参考课程第 1 课的 虚拟单板计算机指南,其中包含创建 Python 虚拟环境、安装 CounterFit 相关 pip 包以及运行counterfit启动 Web 应用的完整步骤。此处仅列出与 GPS 传感器相关的要点:
在电脑上创建一个名为
gps-sensor的文件夹,里面只有一个名为app.py的文件和一个 Python 虚拟环境(.venv),并在虚拟环境中安装 CounterFit 的 pip 包(CounterFit、counterfit-connection等)。额外安装一个 CounterFit shim(垫片)包,它能让 Python 代码通过串口连接与基于 UART 的虚拟传感器通信。务必在已激活虚拟环境的终端中执行:
pip install counterfit-shims-serial确保 CounterFit Web 应用正在运行(在安装了 CounterFit 的虚拟环境终端中执行
counterfit启动,它会自动在浏览器中打开界面)。
提示:如果 5000 端口被其他应用占用,可以在代码中修改连接端口,并用
CounterFit --port <port_number>以其他端口启动 CounterFit(详见第 1 课虚拟设备指南)。
创建 UART GPS 传感器
- 在 CounterFit 界面的Sensors面板中找到Create sensor(创建传感器)区域;
- 展开Sensor type(传感器类型)下拉框,选择UART GPS;
- 将Port(端口)保持默认值
/dev/ttyAMA0不变——这是虚拟 GPS 传感器使用的 UART 端口地址,/dev/ttyAMA0正是树莓派等单板计算机上 UART 硬件串口的典型设备文件名,CounterFit 借此保持虚拟硬件与真实硬件的命名一致; - 点击Add按钮,在端口
/dev/ttyAMA0上创建 GPS 传感器。
传感器创建成功后会出现在传感器列表中。
任务二:编写读取 GPS 数据的 Python 应用
虚拟 IoT 设备现在可以编程来使用这个虚拟 GPS 传感器了。
确保
gps-sensor应用已在 VS Code 中打开;打开
app.py文件;在文件顶部添加以下代码,让应用连接到 CounterFit:
from counterfit_connection import CounterFitConnection CounterFitConnection.init('127.0.0.1', 5000)这段代码从
counterfit-connectionpip 包导入CounterFitConnection类,并初始化到运行在本机127.0.0.1(localhost)、端口 5000 上的 CounterFit 应用的连接。在下方添加以下代码,导入所需库(包括 CounterFit 串口库)并打开虚拟串口:
import time import counterfit_shims_serial serial = counterfit_shims_serial.Serial('/dev/ttyAMA0')这段代码从
counterfit_shims_serialpip 包导入串口模块,然后连接到/dev/ttyAMA0串口——这正是虚拟 GPS 传感器为其 UART 端口使用的串口地址。shim 的意义在于:你在电脑上写这段代码时,代码形态与在树莓派上用物理串口驱动访问 UART 外设完全一致,从而保证虚拟设备代码可以直接移植到真实硬件。再往下添加读取串口数据并打印到控制台的代码:
def print_gps_data(line): print(line.rstrip()) while True: line = serial.readline().decode('utf-8') while len(line) > 0: print_gps_data(line) line = serial.readline().decode('utf-8') time.sleep(1)代码逻辑说明:
- 定义了函数
print_gps_data,把传入的一行数据去掉行尾字符(rstrip())后打印到控制台; - 外层
while True循环不断从串口读取数据。内层循环在每一轮中尽可能多地读取文本行,每读一行就调用一次print_gps_data; - 当某次
readline()返回空行(没有新数据)时,本轮读取结束,程序休眠 1 秒后再次尝试,从而避免忙等待,同时保持 1 秒级的轮询节奏——与虚拟 GPS 传感器每秒发一个位置点的节奏相匹配。
完整的可直接运行代码参见仓库中的 app.py 示例文件。
- 定义了函数
运行该代码。注意要使用与运行 CounterFit 应用的终端不同的终端,这样才能让 CounterFit 应用保持运行状态;
从 CounterFit 应用中改变 GPS 传感器的值(见下一节),控制台就会开始打印传感器数据。
三种数据注入方式:Lat/Lon、NMEA、GPX
在 CounterFit 应用中选择已创建的 GPS 传感器后,可以通过以下三种方式之一设置其数据源(Source),配置完成后点击Set按钮把这些值提交给传感器。
方式一:Lat/Lon(经纬度直接设定)
- 将Source设为
Lat/Lon; - 设置明确的纬度、经度,以及用于获得 GPS 定位(fix)的卫星数量;
- 该值只会发送一次,因此需勾选Repeat复选框,让数据每秒重复发送。
方式二:NMEA(原始语句)
- 将Source设为
NMEA,在文本框中填入若干条 NMEA 语句; - 所有语句都会被发送,且在每条新的 GGA(定位)语句可以被读取之前,会有 1 秒的延迟;
- 你可以使用 NMEA 语句生成类工具(如 NMEA 生成器网站),通过在地图上绘制轨迹来生成这些语句;
- 这些值同样只发送一次,因此勾选Repeat复选框,让全部语句发送完毕后隔 1 秒重复。
方式三:GPX 轨迹文件
- 将Source设为 GPX 文件,上传一个包含轨迹位置点的 GPX 文件;
- GPX 文件可从众多流行的地图与徒步网站(如 AllTrails 等户外轨迹站点)下载。文件以轨迹形式包含多个 GPS 位置点,GPS 传感器会以 1 秒为间隔依次返回每个新位置;
- 值只发送一次,因此同样建议勾选Repeat复选框,让全部位置发送完毕后隔 1 秒重复。
观察原始输出并理解 GGA 报文
程序运行后,你会看到 GPS 传感器的原始输出,形如:
$GNGGA,020604.001,4738.538654,N,12208.341758,W,1,3,,164.7,M,-17.1,M,,*67 $GNGGA,020604.001,4738.538654,N,12208.341758,W,1,3,,164.7,M,-17.1,M,,*67这些看似乱码的输出其实是标准的 NMEA 0183 报文。以这条$GNGGA(GPS Fix Data,GPS 定位数据)语句为例,它包含纬度、经度、海拔、参与定位的卫星数量等信息:
- 纬度部分是
4738.538654,N,采用 NMEA 的(dd)dmm.mmmm度分格式:47 度 38.538654 分,方向字符N表示北纬,因此是正纬度,换算为十进制度约47.6423109; - 经度部分是
12208.341758,W:122 度 08.341758 分,方向字符W表示西经,因此是负经度,换算为十进制度约-122.1390293。
这正是 GPS 传感器输出的原始数据形态。在本课的下一步「Decode GPS sensor data(解码 GPS 数据)」中,你会使用开源 NMEA 解析库把这类原始报文解码为可用的经纬度——虚拟设备与树莓派共用的解码指南见 single-board-computer-gps-decode.md,仓库中也提供了对应的解码版示例代码(在pynmea2解析基础上增加了S/W方向的负值处理),可参考 code-gps-decode 示例。课程 README 末尾还给出了进阶挑战:不依赖第三方库,自己编写一个从 NMEA 语句中提取经纬度的解码器。
小结与验证清单
完成本节后,你的虚拟 GPS 链路应满足以下验证点:
| 验证项 | 预期结果 |
|---|---|
虚拟环境中已安装counterfit-shims-serial | pip install成功,终端已激活.venv |
| CounterFit 传感器列表中存在 UART GPS 传感器 | 端口为/dev/ttyAMA0 |
运行app.py后 CounterFit 状态为 Connected | 应用已连接127.0.0.1:5000 |
| 设置 Lat/Lon 并勾选 Repeat 后运行 | 控制台每秒打印一条$GNGGA...语句 |
| 切换为 NMEA / GPX 数据源 | 语句或轨迹点按 1 秒节奏依次输出 |
至此,你已经成功用虚拟硬件完成了 GPS 传感器编程——无需任何实体设备,代码即可直接复用到树莓派或 Wio Terminal 等真实硬件上,这也是 IoT-For-Beginners 课程「同一套代码,虚拟/真实设备通用」的核心设计思路。
【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考