虽说 micro:bit 的基本功能相对树莓派等开发板来说并不算丰富,但它的处理器有足够多的闪存和 RAM 来实现一个具有基本功能的追踪器,同时 micro:bit 还带有加速计和指南针芯片,这让实现追踪更加方便。下面以气球追踪器为例介绍制造的方法和步骤。
micro:bit 自带 SPI、I2C 和串口,可以通过转接板引出,不需要直接焊接到焊盘上。另外你可以购买一个专用的电池盒。
micro:bit×1
转接板×1
UBlox 模块×1
LoRa 收发器×1
电池盒×1
UBlox 模块
气球追踪器需要一个合适的 GPS,以便在高空中发送位置,另外还需要一个 ISM 频段无线电发射机。最后,我选择了 UBlox 模块。
这个模块包括一个 I2C 端口和常用串口。由于 micro:bit 的串口通常是由 USB 连接到电脑。如果我们使用串口的 GPS 软件,那么开发会变得困难,而 I2C 会让开发更容易一些。
LoRa 收发器
接下来是无线电部分。现在,最受欢迎的是 ntx2b 无线电发射器,但它需要一个串口,所以我没有选择它。我选择了 LoRa 收发器,因为它带有一个 SPI 接口,串口还可以用于调试。
现在可以将所有的硬件连接在一起。因为原型板上没有太多的空间,为了让 GPS 远离其他设备(以便减少干扰),所以我把 GPS 和无线电放在电线尾部。
GPS 软件
有许多的编程方式可以应用于 micro:bit 上,我选择了 MicroPython。
1、我开始使用一些简单的代码,从 GPS 上获取 NMEA 数据流,这只需了几分钟。
2、将树莓派的 Python GPS NMEA 分析器移植过来(只需改变代码使用 micro:bit 的 I2C 库而不是树莓派的串口)。
查看我的另一个项目的测试程序(它是为汽车编写的,因此没有把 GPS 放到飞行模式中)。
https://microbit-micropython.readthedocs.io/en/latest/i2c.html
LoRa 无线软件
测试设备连接好后,只要在 micro:bit 的 REPL 输入少量命令就可以完成了移植。
在 SPI 库中,要删除所有 LoRa 寄存器定义,因为它占用过多的程序。查看结果测程序:
https://gist.github.com/daveake/86f7ba32fa8018acd5e5359674a737e5
为了收到 LoRa 的传输数据,你需要安装另一个 Lora 模块作为接收器,再使用适合的软件。我用自己编写的 C Lora 网关代码进行接收。 C Lora 网关代码:
https://github.com/daveake/lora-gateway
项目组装非常的简单,但是软件还需调整才行。
一旦 GPS 和无线模块开始工作,那么你只需要少量的额外的代码将 GPS 数据作为一个字符串,添加一个前缀(“$$”和有效的 ID)和后缀(“*”以及 CRC),然后通过无线发送结果。然而,当我将 GPS 和 LoRa 代码放在一起,就无法编译。
在 micro:bit 上的代码不能太大,还好它不是太大,然后我删除了一些不必要的代码(主要是在代码中关闭未使用 GPS 的 NMEA 句子),最后编译器可以正常工作。
但是结果并不理想。一旦编译完成就会将产生的字节码加载到 micro:bit 的 RAM,它会将程序中使用的任何数据(变量、堆栈、临时工作区)共用。Python 的本质是内存一直被分配,并在必要时释放,当程序试图分配比可用内存更多的空间时,我的程序将运行很短一段时间后会因为内存不足而崩溃。这是它在崩溃前的工作结果。
因此我不得不减少内存占用。我习惯在微控制器上用 C 语言,但 MicroPython 需要不同的技术。例如,在微存储器上 C 通常位于闪存中,对 RAM 中数据的限制要少,所以有时你可以重写代码以使用较少的 RAM,而不必担心新代码使用更多的代码空间。而不像在 MicroPython 中,一切都会在RAM 共享。我也做了一些尝试,但情况更糟(通过在主循环中调用 gc.free_ram())。
然后,我通过移除不需要的代码来增加剩余 RAM。这样做之后,程序变得稳定。每个循环都会分配内存,自由内存会不断增加和减少,然后最终释放。
容易改进是用 LED 显示 GPS 卫星的数量,只需导入所需的模块,而不是整个 micro:bit 库。代码的最相关的部分原来是建立一个 NMEA。在 C 中,只需为需要解析的最长语句分配足够的内存,然后使用指针或数组将传入的字节放入内存中,检查缓冲区溢出的过程。在 Python 中的字符串是不可变的,你不能用同样的方法。可以用“string = string + new_character”。
当然,Python解释器将为结果字符串分配新内存,将旧字符串标记为“不再使用”,因此稍后可以释放它,最终会有很多闲置的内存等待释放。现在,我的 NMEA 代码中每当收到新的字节就会释放内存。我曾改变代码使用 bytearrays,这是最接近 C 语言的方法,但内存还略有下降(我假设原来占用更多的空间),所以我回到原代码。最终,我重写 NMEA 代码,使用二进制 UBX 协议代替。
代码已经连续运行了 12 个多小时,而空闲内存图是实心的(在主循环中每一次都在同一个点上测量)。我确实还需要添加飞行模式代码,这个应该问题不大。如果一切顺利的话,选择一个合适的天气就可以开始飞行了。
最后,这是我最近通过 Python Lora 网关程序接收的测试结果。