亲,“电路城”已合并升级到更全、更大、更强的「新与非网」。点击查看「新与非网」

本网页已闲置超过3分钟,按键盘任意键或点击空白处,即可回到网页

自制车载多功能GPS追踪器

发布时间:2022-10-31
分享到:

自制车载多功能GPS追踪器

发布时间:2022-10-31
分享到:

项目将位置发送给Thinger。通过IO仪表板与地图视图,短信回复的请求与地图链接和触发通知。

这个项目一开始是一个简单的“GPS追踪器的想法”,结果变成了一个“多功能GPS追踪器”。作为我的第一个项目,学习曲线是陡峭的,因此我总是开放的输入,反馈和改进设计!

追踪器我打算放在我的车里,有以下功能:

  • 追踪GPS坐标,公布最后的位置thinger.ioIoT云仪表盘每2分钟一次(在地图上显示)。发布到thinger.io使用HTTP POST请求。
  • 回复SMS命令并返回指向当前或最后已知位置的谷歌地图链接(如果没有可用的当前位置,则最后已知位置)。
  • 每隔XX公里发送一条短信通知(这个想法是让追踪器提醒我每隔4000公里清空我的捕油箱)。这是一个可定制的软件“里程表”。

在这个项目中我意识到,Arduino在可用内存方面是多么的“有限”,我必须学习减少开销和编写高效代码的技术(至少我尝试过)。我还使用了轻量级库来将所有内容装入芯片和可用的RAM中。

使用的组件如下:

  • NEO-6M GPS装置。这似乎是一个非常受欢迎的GPS设备,在Ebay和类似的地方很便宜。与GPS的通信将采用硬件串行方式。
  • GPS天线。任何兼容的都可以,然而,我发现Ebay上最便宜的不那么好,即接收不好/卫星计数低。也许我只是不走运,第一个天线,但我必须得到另一个更好的质量稳定的接收。
  • 用于GSM和GPRS连接的SIM900开发板。这个项目还应该与SIM800和兼容的模块一起工作,但是不能保证。与SIM900的通信将采用软件串行。
  • Arduino莱奥纳多董事会。我用过达芬奇的画板专用硬件串行线,因为我们需要两条串行线。虽然它可以使用一个普通的UNO板,你必须断开GPS下载软件,而且你将没有串行监视器调试。我们需要两条串行线(一条用于GPS,另一条用于SIM900板);一个软件串行和一个硬件串行。
  • SD卡读卡器(我使用的Adafruit读卡器是5V兼容的(使连接到5V SPI头很容易)。其他更便宜的模块可能也一样好用。Micro SD卡将用于存储旅行距离。警告:如果按照我的原理图,请确保您的SD卡阅读器支持5V电源,许多SD卡阅读器只使用3.3V。使用不正确的电压极有可能损坏电子设备。与SD卡阅读器的通信将采用SPI接口。
  • LED和电阻来制作状态指示电路(电源和GPS锁定LED)。
  • 有数据的SIM卡。
  • 我还设计了一个可3D打印的附件STL文件,可以直接打印在3D打印机上。

首先,我们需要安装必要的库。我在这个项目中使用了以下库:

  • NeoGPS用于GPS追踪和解码。可以直接从Arduino IDE中的库管理器安装。
  • 时间库(用于UTC时区转换)
  • PetitFS用于读写SD卡

短信命令

SMS上可用的命令如下(均为大写字母)。这些是提供的代码中支持的命令;您可以为自己的项目/需求添加/删除命令:

  • “POS”如果坐标可用,则返回带有谷歌Maps链接的坐标。否则,返回最后的已知位置。
  • “GETKM”返回自上次“重置”以来的当前距离。
  • “RESETKM”将距离计数器设置为0(重置里程表)。

设置NeoGPS
我们使用NeoGPS库来实现性能和资源使用,而不是像tinygp++这样的替代方案。它消耗的内存非常少,这是必需的;否则,我们将得到低内存和稳定性的警告。

库安装完成后,修改库安装路径中的文件GPSPort.h(给出的示例是针对OS X的—对于Windows,您将在不同的位置找到库)

将GPSPort.h中的所有内容替换为以下内容:

#ifndef GPSport_h
#define GPSport_h
#define gpsPort Serial1
#define GPS_PORT_NAME "Serial1"
#define DEBUG_PORT Serial
#endif

该文件包含NeoGPS库使用的定义。如果你使用的是不同的Arduino板,这是你定义到GPS接收器的串行线的地方。"Serial2", "Serial3"用于Arduino MEGA。

记录的准确性

需要注意的是,GPS并不是最精确的测量和积累距离的方法,因为即使在静止状态下,位置也会轻微漂移。你可以通过站在同一个地方,观察GPS坐标在每次读数时都是不同的来测试这一点。对于这种应用,精度不那么重要,因此较小的偏差是可以的。我试图解释坐标上的小漂移,软件只增加了超过10米的运动距离(所有低于10米的运动假设是静止的)超过15秒。

还要记住,距离是按直线计算的,而汽车行驶的实际距离取决于道路、弯道等。我已经将采样率设置为15秒,如果你想要更高的精度,你可以降低这个值。

设置PetitFS
这个库是一个超轻量级的库,用于对FAT格式的SD卡进行读写。我花了一些时间来弄清楚这是如何工作的,因为文档几乎不存在,有些地方甚至是错误的/过时的。提供的库示例代码甚至无法编译。它有很多限制(与Arduino的SD库或SDFat等“普通”库相反):

  • 不能创建文件。只能写入现有的文件。
  • 无法扩展文件大小。
  • 无法更新文件的时间戳。
  • 不能向文件追加数据(每次都重写文件)。
  • 任何时候只能打开一个文件。

为什么要使用一个小的、有限的、看起来有很多缺陷的库呢?

我尝试了一些库,包括Arduino SD库,SDFat和fat16lib。它们都太大了,无法将所有代码放入芯片中,所以为了不删除功能,我使用了这个库(标准的Arduino SD库大约多占用12%的空间)。即使有所有这些怪癖和限制,它仍然提供了我们这个应用程序所需要的:简单地对单个值进行读写以用于存储。

如果您不使用所有的代码,并且有足够的空间可以挤进一些额外的代码,那么使用标准SD库之类的库就容易得多了。

从PetitFS库文件夹中打开文件pffArduino.h。修改SD_CS_PIN为10。这是SS引脚,用于与带有SPI的SD卡通信。

从库文件夹中打开文件pffconf.h。通过将设定值从1切换到0来禁用以下选项:

  • _USE_DIR
  • _USE_LSEEK
  • _FS_FAT12
  • _FS_FAT16

通过禁用这些选项,编译后的程序占用更少的空间——这是需要的;最后的草图大概花了。96%的存储空间。

在第一次导入库时,你会得到一个编译错误,可以忽略(第二次编译时错误没有显示-仍然不明白为什么)。然而,如果你想修复这个问题(它会在每次你启动Arduino IDE ->编译时重新出现),添加缺失的函数返回参数“FRESULT”,如上图所示。它在库文件夹中的pff.cpp文件中。

准备SD卡

我在这个项目中使用了Micro SD卡。由于库不能自己创建文件,因此在使用前在卡上创建文件"dist.txt"和"settings.txt"是很重要的。我建议从这个项目页面复制附加的“dist.txt”和“settings.txt”文件,因为这些文件已经有正确的格式和工作(图书馆对文本格式和内容非常挑剔)。

在将文件放入Micro SD卡之前,请确保正确格式化该卡(如FAT32)。我推荐使用官方的“SD卡格式化器”。

确保SD卡工作正常(正确读写文件)

PetitFS库对输入文件非常挑剔。如果您启动设备,串行监视器中没有显示输出(只是空白),它很可能被卡在“循环”中,它试图从卡中读取文件,但由于某种原因无法读取(initializeSD()函数)。我有无数的文本文件,它由于某种原因已经无法读取,因此我包括了我使用的工作引用的文本文件。把这些参考文件放在SD卡上,它应该能够正确地读写它。

另一种选择是用一个比其写入的数字更大的数字填充文本文件。我没有对此进行测试,但是由于库本身不能扩展文件大小,所以我认为这可能是个问题。

PetitFS将字符数组的整个长度写入文件,因此您将在实际数字前面看到空格(除非数字大到足以填满数组—“数组”长度在代码中定义)。在对文件进行更改时,必须保留这些空格——因为petfs不能更改文件大小,如果更改了字符的数量,则会导致问题。

如果您想让里程表从“0”开始,请将“dist.txt”文件设置为“0”,或任何其他数字,以方便验证其工作,例如发送“GETKM”命令来验证短信回复。

在settings.txt中设置通知触发距离,里程表触发通知短信的距离(以米为单位)。

准备好SIM900单板
在我们可以使用SIM900板之前,必须在它上设置一些东西。

电源

Arduino板无法提供足够的电源,所以我们必须使用外部电源。由于峰值可达2A,请确保使用在5V-9V DC下能提供至少2A的电源;它使用的是管状5.5mm连接器。

电源选择器

紧挨着直流插座的是电源选择器。如需使用外置电源,请按上图所示移动滑块。

连续选择器

通过如上所示的对齐跳线,设置板使用软件串行。

软件触发

您可以在软件中打开/关闭SIM900,而不是每次都手动按下电源键。为此,必须对名为R13的跳线进行焊接。然后,通过连接SIM900引脚#9到Arduino引脚#7(如图所示),为单板供电。

如果保持“手动供电”功能,则可以删除代码中的“SIM900power()”函数。

移除vesim卡PIN锁

在使用SIM卡之前,请务必去掉PIN锁。这可以通过将它插入任何普通手机,并从适用的设置菜单中删除pin锁来实现。

还要注意,示意图中的SIM900模块可能看起来与实际的板不同,然而,引脚布局是正确的,这是最重要的部分。

SIM900固件版本

在芯片上加载正确版本的固件是非常重要的。这是因为在固件版本B10之前,不支持正确设置HTTP POST报头的命令之一。这意味着您至少需要有版本B10或更高的http通信才能正常工作。具体来说,对于较低的固件版本,它将无法在http头中设置“内容类型”。如果在post请求中内容类型没有设置为“application/json”,它将被服务器拒绝。

使用以下AT命令检查固件版本:

AT+CGMR

SIM900芯片将在输出控制台中提供当前固件版本。在setup()部分的末尾输入以下命令,打印启动时的固件版本:

SIM900.println( F("AT+CGMR") ); 

在我的情况下,它将显示以下内容:

Revision:1137B01SIM900M64_ST_AM

这是该芯片(“B01”)可能的最老固件版本,所以我更新到版本B10: 1137B10SIM900M64_ST。更新的固件应该也能工作。

代码的调整
为了使代码适合你自己的项目,需要做一些调整:

  • 更改APN(网络提供者)信息。
  • 修改thinger.ioURL来匹配您自己的(URL将更新请求链接到您自己的带有访问令牌的“bucket”)。
  • 设置正确的时区。
  • 设置短信通知的触发距离
  • 设置(或禁用)短信通知文本。
  • 设置默认通知电话号码。

APN提供者

void connectGPRS(){
...
 SIM900.println( F("AT+SAPBR=3,1,\"APN\",\"TeleXXX\"") );
 delay(1000);
 updateSIM900();
...

在connectGPRS()函数下,您将找到由网络提供商提供的APN名称,如上所示为“TeleXXX”。将其替换为您自己的APN名称。

AT
OK
AT+CMGF=1
OK
AT+CNMI=1,2,0,0,0
OK
AT+SAPBR=3,1,"CONTYPE","GPRS"
OK
AT+SAPBR=3,1,"APN","TeleXXX"
OK
AT+SAPBR=1,1
OK
AT+SAPBR=2,1
+SAPBR: 1,1,"36.57.240.233"
OK 

以上:连接工作时connectGPRS()函数的输出。所有命令都应该返回“OK”状态。

时区

#define UTC_OFFSET 1  // set time zone offset, i.e. 1 = UTC+1

在“定义”部分,根据您的需要设置时区。代码设置为UTC+1。

短信通知

void loop() {
...
 // sends notification on SMS if the total distance exceeds 4000km
 if (totalDistance > triggerDistance) {
   char sms_msg[160];
   char distanceTotalMsg[10];
   itoa( (totalDistance / 1000) , distanceTotalMsg, 10);
   sprintf(sms_msg, "Empty catchtank! Current distance: %skm", distanceTotalMsg);
   textMessage = "";
   totalDistance = 0;
   // sets the default phone number to trigger notification
   number = DEFAULT_NUMBER;
   sendSMS(sms_msg);
 }
 ...
}

触发通知的代码部分(在主循环()中)。

如果不需要任何触发通知,则注释掉/删除此部分。或者将文本更改为有用的内容。

一旦“里程表”(累计距离)达到“settings.txt”文件中设置的配置距离,就会触发该通知。

默认的电话号码

这是被触发的通知被发送到的电话号码(因为通知没有要回复的“发件人”号码)

// phone number for triggered notification
#define DEFAULT_NUMBER "+4712345678" 

等待串行连接

取消代码中下面一行的注释也是一个好主意。这使得Arduino板等待串行连接激活,即串行监视器进行调试。这样,在串行行激活之前,您就不会错过代码开头的任何调试消息。

记得在从外部电源为Arduino供电之前删除/注释这一行,否则它将在无限循环中停止,直到连接到PC。

// while (!Serial);     // wait for serial port to connect - for ATmega32u4 (Leonardo)

io集成
在这一节我不会详细介绍如何设置thinger。IO是非常直接的;你必须创建一个帐户和一个“桶”通过他们的网站接收数据,和一个“设备”,我们将连接。“桶”是接收数据的数据库。“设备”是我们代码的连接点,在这里我们决定如何处理数据(在我们的例子中,填充“桶”数据库)。

创建一个“bucket”,上面有你自己的名字和描述。

现在,按照官方文档https://docs.thinger.io/quick-sart/devices/http-devices中的描述创建一个“HTTP设备”。

使用较短的设备名称。由于设备名称是生成授权密钥的算法的一部分,我发现较长的设备名称也会生成较长的授权密钥。针对这个问题,授权密钥很快就超过了从Arduino发送字符串时使用的256个字符缓冲区。可能有一些更好的方法来解决这个问题,但我发现最简单的方法是保持设备名称简短,避免这个问题。

在设备回调>设置部分,确保“写桶”设置指向之前创建的桶。这告诉“设备”将传入的数据写入我们的数据库。

在设备回调>概述部分,记录方法URL和授权头(没有关键字“holder”的长字符串)。

把数据发送给一个小东西。io我们在HTTP POST请求中使用“授权URL”。然后,您必须用您自己的密钥替换代码中的URL和授权密钥。

在postDataThinger()函数中,你会发现调用(实际的授权键被打乱):

SIM900.println( F("AT+HTTPPARA=\"URL\",\"http://backend.thinger.io/v3/users/tom/devices/CT/callback/data?authorization=eyJhbGciOiJIUzI1NiIsInR5cdfkjowiuerdf.sdfsdf.wekrjciI6InRvcm1vZCJ9.AR1gWvIZB9KmtI-5Z12YXKuchPTGn58AkwBJSZQIoxQ\"") );

然后,您必须将代码中的URL和授权密钥替换为您自己的密钥,这些密钥是通过按照上面提供的链接中的说明生成的。

http://backend.thinger.io/...

SIM900不支持SSL(至少我没有让它工作),所以一定要将“https://”更改为“http://”。thinginger API还支持非ssl连接。这一点非常重要。如果您一直使用“https”,它将无法工作。当一切正常时,串行监视器应该在传输http post请求时给出一个“200 - OK”答复。

在AT命令"AT+HTTPACTION=1"(发送HTTP POST请求)之后,你应该在串行监视器中收到如下回复:

+ HTTPACTION: 1200, 0
如果你收到一个“400 -坏请求”的答复或类似的

+ HTTPACTION: 0400年,51
很可能是URL有问题,例如:“https”而不是“http”,“授权密钥”语法错误,等等。当您收到“200 - OK”消息时,数据应该显示在如下所示的东西桶中。你也可以收到一个400 -“坏请求”,如果你没有正确的固件,如前所述。

上面是数据到达后桶的视图。内容(数据列)是由代码中的HTTP POST请求语法设置的,没有任何设置。io是必要的。

下面是当一切正常时HTTP POST请求的串行输出。+HTTPACTION: 1,200,0表示更新成功。

AT+HTTPINIT
OK
AT+HTTPPARA="CID",1
OK
AT+HTTPPARA="URL","
OK
AT+HTTPPARA="CONTENT","application/json"
OK
AT+HTTPDATA=84,10000
DOWNLOAD
OK
AT+HTTPACTION=1
OK
+HTTPACTION:1,200,0
AT+HTTPTERM
OK 

然后,可以使用使用桶作为数据源的maps小部件在thinger中轻松设置仪表板。

更多其他的数据?

除了经度、纬度和日期/时间之外,您是否希望推送更多的数据?只需向http请求添加更多数据字段,如下所示。

格式为{"field1 name": field1, "field2 name": field2, "field3 name": field3}

sprintf(httpContent, "{ \"longitude\" : %s , \"latitude\" : %s , \"date\" : \"%s %s\" }", tempstrLong, tempstrLat, date1, time1);

上面的sprintf命令编译发送到thinger的数据字符串。语法非常严格,您必须以完全相同的方式添加新的数据字段。示例在代码(注释部分)中给出。一个好主意是记录将显示字符串的命令的串行监视器打印。然后添加“field4”等等。

外壳
我使用了一个完整的3D打印外壳。这是为这个项目所使用的pcb设计的。安装时使用M3螺钉。

它被设计为一个7x5cm的LED“电路”焊接板,而不是面包板。如果使用面包板,就用一些胶水代替。GPS和焊锡板(“面包板”)安装在顶部外壳。使用小垫片,以便pcb在顶部外壳的最佳安装。

我也保持了安装点在顶部套管固体(没有孔),使更容易打印没有支持。用3毫米的钻头打开这些。

在0.2mm无支架的情况下打印效果良好。

连接汽车电池/电源
可能有数百种方法可以做到这一点,所以我没有唯一的答案,也没有最好的答案;如何把它连接到汽车电池上。这完全取决于您的应用程序,但我将快速描述我的解决方案。

我想让这个设备从汽车启动,这样就不会直接连接到电池(在汽车关闭时也会充电)。所以我把它连接到“香烟插口”电路上,它已经随汽车开关了。如果你想让它在汽车熄火时也能在线,你就得想办法把它连接到电池上。对于大多数汽车来说,香烟插口随着汽车关闭,但你必须为你自己检查这个。我不会显示我的确切线路,因为这也将是不同的每辆车。你也可以在两者之间放置一个电池组,以便在汽车关机(或被盗)后保持设备工作数小时。

当然你也可以用一个适配器,比如那些USB手机充电器,但这违背了我隐藏它的目的(以防车被偷)。我们也有两个电源,Arduino板和SIM900模块。我使用了一个降压模块,从12V-5V转换(实际输入范围据说是9V-20V)。它的质量可能不太好,但到目前为止还可以工作。

降压模块将12V输入转换为5V输出到两个USB母连接器。然后,我将Arduino和SIM900模块连接到每个USB输出,为它们供电。可能还有其他更“专业”的解决方案,但这个方案既便宜又有效。

我测量过GSM活动期间的功耗约为110maH,因此功耗非常小。它可能会在GSM覆盖较差的地区消耗更多的电力。

已知的问题
如果SMS命令与该字符同时收到。IO HTTP请求被处理(当数据被推到thinginger)命令将不会被软件拾取。此时,您将不会收到短信回复。几秒钟后发送一个新命令,它将再次工作。我没有为此做一个变通,因为这不是一个大问题。如果有人应该对此进行修复,请随意分享。

此外,如果Arduino在一个没有网络覆盖的地区启动,当网络重新可用时,它不会重新连接,因为它只在启动时连接。

如果您对此项目有任何想法、意见或问题,请在下方留言。

以上内容翻译自网络,原作者:tormods,如涉及侵权,可联系删除。

加入微信技术交流群

技术交流,职业进阶

关注与非网服务号

获取电子工程师福利

加入电路城 QQ 交流群

与技术大牛交朋友

讨论