在树莓派上安装G-Mouse GPS接收器并读取GPS数据
我想给我的树莓派(具体型号是Clockwork uConsole)增添GPS功能,于是在相关渠道找到了这款带2米延长线的USB GPS接收器。在Drupal开发中,常常也需要对各种设备进行整合,就像给树莓派添加GPS功能一样,精准地将不同功能融入整体系统。
这个GPS设备有一个USB接口和一根2米长的电缆,而且接收器本身带有磁性,能附着在很多不同的表面上。我对它能和树莓派很好地配合使用挺有信心,实际情况也确实如此,安装过程并不复杂,只需要安装几个额外的工具,就能确保它输出正确的数据。
在这篇文章里,咱们来看看插入GPS接收器后会出现什么情况,然后介绍几个能验证GPS接收器是否正常工作的软件包。这里假设你运行的是最新版本的树莓派操作系统。
一、插入GPS接收器
把GPS设备插入系统后,它会创建一个名为/dev/ttyAMC0的文件(或者资源)。不过这个文件也可能位于/dev/ttyACM1,这主要取决于你的系统和设置,但大致就在这个位置附近。
你可以用cat命令来流式传输该资源,输入下面的命令就行。
cat /dev/ttyAMC0
输出的信息大概像下面这样。
$GPVTG,,T,,M,0.177,N,0.328,K,A*2B
$GPGGA,21011.00,510.33664,N,0021.33939,W,1,04,3.99,113.8,M,48.4,M,,*48
$GPGSA,A,3,09,11,17,19,,,,,,,,,5.78,3.99,4.18*01
$GPGSV,2,1,06,04,,,32,09,54,198,33,11,20,307,27,12,02,315,17*42
$GPGSV,2,2,06,17,23,215,25,19,37,242,35*77
$GPGLL,510.33664,N,0021.33939,W,201011.00,A,A*79
要是你看到这样的数据流,就说明一切正常,可以开始从GPS设备读取数据了。通常可以不使用sudo来运行这个命令,如果不行的话,你得把你的用户添加到“dialout”组中。
sudo adduser [你的用户名] dialout
这样你应该就能访问该资源了。
二、GPS守护进程
要使用这些数据,得安装一个叫GPSD的守护进程。在Drupal模块开发里,也会有类似这种基础服务的搭建,来保证系统各个模块能正常协作。
GPSD能让程序连接到GPS接收器,不用直接访问GPS硬件本身。也就是说,程序不用对已安装的GPS设备的数据进行解码,而是可以访问一个包含GPS信息的JSON数据流,这种格式更容易读取。
安装GPSD,运行下面的命令。
sudo apt install gpsd
打开/etc/default/gpsd配置文件,找到名为GPSD_OPTIONS的选项。这个选项指向GPS资源的位置,也就是我们之前查看的文件。
把文件名添加到GPSD_OPTIONS设置中。
GPSD_OPTIONS="/dev/ttyACM0"
更改这个设置后,可以用下面的命令重启守护进程。
sudo service gpsd restart
或者重启树莓派,效果是一样的。
你可以通过telnet连接到端口2947来测试是否一切正常。
telnet localhost 2947
Trying ::1...
Connected to localhost.
Escape character is '^]'.
{"class":"VERSION","release":"3.22","rev":"3.22","proto_major":3,"proto_minor":14}
然后,可以用“?POLL;”命令从GPS守护进程获取数据。
?POLL;
{"class":"POLL","time":"2025-04-12T21:23:23.767Z","active":0,"tpv":[],"gst":[],"sky":[]}
要是你想从设备接收数据,也可以用WATCH命令来激活设备。
?WATCH={"enable":true,"raw":true};
{"class":"DEVICES","devices":[{"class":"DEVICE","path":"/dev/ttyACM1","driver":"u-blox","subtype":"SW 1.00 (59842),HW 00070000","subtype1":"PROTVER 14.00,GPS;SBAS;GLO;QZSS","activated":"2025-04-12T21:25:04.062Z","flags":1,"native":1,"bps":9600,"parity":"N","stopbits":1,"cycle":1.00,"mincycle":0.02}]}
{"class":"WATCH","enable":true,"json":false,"nmea":false,"raw":0,"scaled":false,"timing":false,"split24":false,"pps":false}
这只是显示了从服务中流出的原始数据。接下来,咱们用一些客户端来读取这些数据。
三、读取GPS数据
要从GPSD读取GPS数据,可以安装另一个叫gpsd - clients的软件包。这其实是一个元软件包,里面包含多个不同的程序,能用来测试GPS接收器,确保它正常工作。
用apt安装gpsd - clients。
sudo apt install gpsd-clients
安装后会添加多个不同的程序,下面介绍几个。
xgps
xgps应用程序为GPS数据提供了一个图形用户界面(GUI),用下面的命令就能启动它。
xgps
它会显示GPS接收器可见范围内的卫星以及它们向系统提供的信息。
要注意的是,这个应用程序的功能不止你看到的这些,只是我的树莓派屏幕会截断包含实际GPS数据的下半部分,而且窗口也无法调整大小,所以除非你有足够大的屏幕,不然这个工具主要用于确认是否接收到了信号。
cgps
cgps程序是一个命令行工具,它能读取GPS信号,还会提供大量关于你的位置、速度和海拔的信息。
用下面的命令运行该程序。
cgps
输出会显示我们的GPS数据和转换后的卫星数据。你得让GPS运行几分钟,收集所需的所有信息,之后才能看到经度和纬度。要是能在右侧看到卫星数据,就说明一切工作正常。如果你不想看到来自gpsd守护进程的原始数据流,可以用“-s”标志来隐藏JSON数据。
gpsmon
gpsmon程序是另一个命令行应用程序,它能将不同类型的GPS数据转换为坐标数据。
要运行gpsmon,在命令行中输入下面的内容就行。
gpsmon
它会在左侧显示卫星信息,在右侧显示解码后的GPS信息。
有意思的是,我们可以强制gpsmon以NMEA格式从GPS设备读取数据,NMEA格式是海事GPS系统使用的一种不同类型的GPS数据。为此,使用--nmea标志。
gpsmon --nmea
这会在输出的顶部显示我们的经度和纬度坐标,下方显示卫星数据。
四、使用GPS数据
现在已经验证了可以读取GPS数据,接下来就能围绕这些信息编写程序了。首先可以试试用telnet和端口2947,但GPS守护进程库提供了多个可用于读取GPS数据的函数。
为此,需要安装libgps - dev,这样才能访问相应的头文件。
sudo apt install libgps-dev
接下来,要编写一些代码,使用GPS函数从GPS数据中读取信息。下面的代码会读取GPS坐标并把它们打印出来。
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <gps.h>
#include <math.h>
#define SERVER_NAME "localhost"
#define SERVER_PORT "2947"
struct gps_data_t g_gpsdata;
int ret;
int main(void) {
// 1) 尝试打开GPS
ret = gps_open(SERVER_NAME,SERVER_PORT,&g_gpsdata);
if (ret != 0) {
printf("[GPS] 无法打开... 退出。\r\n");
return -1;
}
// 2) 启用JSON流 - 同时启用监控
(void)gps_stream(&g_gpsdata, WATCH_ENABLE | WATCH_JSON, NULL);
// 3) 等待来自GPSD的数据
while (gps_waiting(&g_gpsdata, 5000000)) {
sleep(2);
if (-1 == gps_read(&g_gpsdata, NULL, 0)) {
printf("读取错误!!退出...\r\n");
break;
}
else {
if(g_gpsdata.fix.mode == MODE_2D || g_gpsdata.fix.mode == MODE_3D) {
if (isfinite(g_gpsdata.fix.latitude) && isfinite(g_gpsdata.fix.longitude)) {
printf("[GPS DATA] 纬度, 经度, 使用的卫星数量, 模式 = %lf, %lf, %d, %d\r\n" , g_gpsdata.fix.latitude, g_gpsdata.fix.longitude,g_gpsdata.satellites_used,g_gpsdata.fix.mode);
}
else {
printf(".");
}
}
else {
printf("正在等待定位...\r\n");
}
}
}
// 优雅地关闭...
(void)gps_stream(&g_gpsdata, WATCH_DISABLE, NULL);
(void)gps_close(&g_gpsdata);
return 0;
}
把这个文件保存为“gps.c”,然后运行下面的命令来编译该文件,重要的是用“-lgps”标志将GPS库注入编译器。
gcc gps.c -o gps -lgps
现在你应该有一个名为“gps”的程序,运行这个程序就能从GPS守护进程中读取GPS数据。输出结果如下所示。
/gps
正在等待定位...
正在等待定位...
正在等待定位...
[GPS DATA] 纬度, 经度, 使用的卫星数量, 模式 = 53.405161, -2.361825, 0, 3
[GPS DATA] 纬度, 经度, 使用的卫星数量, 模式 = 53.405161, -2.361825, 7, 3
[GPS DATA] 纬度, 经度, 使用的卫星数量, 模式 = 53.405161, -2.361825, 7, 3
[GPS DATA] 纬度, 经度, 使用的卫星数量, 模式 = 53.405161, -2.361825, 7, 3
[GPS DATA] 纬度, 经度, 使用的卫星数量, 模式 = 53.405161, -2.361825, 7, 3
现在我们有了读取GPS数据的方法,就可以把数据写入文件,创建基于时间的运动记录。由此可见,将GPS数据集成到编写的程序中并不难,就像在Drupal11中进行功能扩展时,合理利用现有资源,也能轻松实现新功能的添加。
五、总结
在Linux系统上从GPS加密狗读取数据挺容易的。一旦通过gpsd验证能接收到数据,就能编写多个程序,通过端口2947来读取GPS数据。要是不使用gpsd库,就得把其中包含的数据解码为GPS坐标。依靠上述部分代码,我能用Clockwork uConsole记录在英国乡村的一次徒步旅行。
GPS加密狗内置了电池,可以将最后记录的数据保留几分钟,这意味着即便关闭系统,也能通过轮询快速获取结果。
要注意,正确设置时间对于获取准确的GPS数据很关键。要是得到的结果异常,得确保你的系统时间设置正确。
这里显示的所有位置都不是我公司的实际地址,这些数据都是在英国乡村外出时生成的。


