{"id":2019,"date":"2017-02-10T10:23:27","date_gmt":"2017-02-10T10:23:27","guid":{"rendered":"http:\/\/www.daveakerman.com\/?p=2019"},"modified":"2017-02-10T10:26:26","modified_gmt":"2017-02-10T10:26:26","slug":"bbc-microbit-balloon-tracker","status":"publish","type":"post","link":"http:\/\/www.daveakerman.com\/?p=2019","title":{"rendered":"BBC Microbit Balloon Tracker"},"content":{"rendered":"<p>I&#8217;ve been meaning to do this for a while, and a short gap between projects gave me some time to try.<\/p>\n<p>The Microbit is (yet another) educational SBC, sitting somewhere between the Codebug and a Raspberry Pi. \u00a0Its processor has plenty enough flash memory and RAM to run a basic tracker (but more on that later), plus it has accelerometer and compass chips.<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter size-full wp-image-2020\" src=\"http:\/\/www.daveakerman.com\/wp-content\/uploads\/2017\/02\/microbit.jpg\" alt=\"\" width=\"640\" height=\"360\" srcset=\"http:\/\/www.daveakerman.com\/wp-content\/uploads\/2017\/02\/microbit.jpg 640w, http:\/\/www.daveakerman.com\/wp-content\/uploads\/2017\/02\/microbit-300x169.jpg 300w\" sizes=\"(max-width: 640px) 100vw, 640px\" \/><\/p>\n<p>Importantly, the Microbit has SPI and I2C busses plus a serial port, all brought out to the edge connector on the bottom. Rather than solder directly to the pads, I bought an edge connector and teeny prototyping board:<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter size-full wp-image-2021\" src=\"http:\/\/www.daveakerman.com\/wp-content\/uploads\/2017\/02\/microbit_socket.png\" alt=\"\" width=\"487\" height=\"430\" srcset=\"http:\/\/www.daveakerman.com\/wp-content\/uploads\/2017\/02\/microbit_socket.png 487w, http:\/\/www.daveakerman.com\/wp-content\/uploads\/2017\/02\/microbit_socket-300x265.png 300w\" sizes=\"(max-width: 487px) 100vw, 487px\" \/><\/p>\n<p>I also bought a battery holder with cable and plug to suit the micro JST connector on the Microbit.<\/p>\n<h2>Balloon Tracker Hardware<\/h2>\n<p>To make a balloon tracker, we also need to connect a suitable GPS (by which I mean, one that still sends positions when at high altitudes) and an ISM band radio transmitter. \u00a0I chose a <a href=\"https:\/\/store.uputronics.com\/index.php?route=product\/product&amp;path=60_64&amp;product_id=72\">UBlox module from Uputronics<\/a>:<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"size-large aligncenter\" src=\"https:\/\/store.uputronics.com\/image\/cache\/catalog\/GPS-Modules\/picobreakout-228x228.jpg\" width=\"228\" height=\"228\" \/><\/p>\n<p>Usefully, this design includes an I2C port as well as the usual serial port. \u00a0Since the Microbit serial port is normally used by the debug connection to a PC, software development becomes more difficult if we use that serial port for the GPS, so I2C makes life much much easier.<\/p>\n<p>Now for the radio. \u00a0The most popular HAB option is the NTX2B radio transmitter, but that also needs a serial port, so instead I opted for a <a href=\"https:\/\/store.uputronics.com\/index.php?route=product\/product&amp;path=61&amp;product_id=69\">LoRa transceiver from Uputronics<\/a>:<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"size-large aligncenter\" src=\"https:\/\/store.uputronics.com\/image\/cache\/catalog\/Radios\/Hope-Microelectronics-RFM98W-433S2-228x228.jpg\" width=\"228\" height=\"228\" \/><\/p>\n<p>This has an SPI interface, so the serial port remains free for debug purposes.<\/p>\n<p>The first job was to get the devices wired together. \u00a0There&#8217;s not much space on this prototyping board, and it can be useful to keep the GPS away from the other devices anyway (less interference), so I put the GPS and radio on wire tails:<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter size-large wp-image-2023\" src=\"http:\/\/www.daveakerman.com\/wp-content\/uploads\/2017\/02\/mbit_tracker-768x1024.jpg\" alt=\"\" width=\"640\" height=\"853\" srcset=\"http:\/\/www.daveakerman.com\/wp-content\/uploads\/2017\/02\/mbit_tracker-768x1024.jpg 768w, http:\/\/www.daveakerman.com\/wp-content\/uploads\/2017\/02\/mbit_tracker-225x300.jpg 225w, http:\/\/www.daveakerman.com\/wp-content\/uploads\/2017\/02\/mbit_tracker.jpg 990w\" sizes=\"(max-width: 640px) 100vw, 640px\" \/><\/p>\n<h2>GPS Software<\/h2>\n<p>There are several options for writing code for the Microbit, and I opted for MicroPython as I&#8217;ve been writing a lot pf Python lately, using the Mu editor\/downloader. \u00a0I started with some simple code to grab the NMEA data stream from the GPS, and this took just minutes to get going:<img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-large\" src=\"https:\/\/pbs.twimg.com\/media\/C4K86aOWYAAHjGk.jpg:large\" width=\"933\" height=\"757\" \/><\/p>\n<p>I then ported my Pi Python GPS NMEA parser (which meant, just changing the code to use \u00a0the Microbit I2C library rather than the Pi serial port). \u00a0You can see my test program <a href=\"http:\/\/microbit-micropython.readthedocs.io\/en\/latest\/i2c.html\">here<\/a> (but please don&#8217;t use that for a flight, as it was written for car use and therefore doesn&#8217;t put the GPS into flight mode!).<\/p>\n<h2>LoRa Radio Software<\/h2>\n<p>I also have LoRa Python code from another project, so after testing that the device was connected OK (a few commands typed into the Microbit REPL interpreter), I ported that over. \u00a0The changes were for the SPI library, plus I had to remove all the LoRa register\/value definitions as they made the program source too large; the source is compiled on the device, so the compiler has a rather limited RAM workspace. \u00a0You can see the resulting test program <a href=\"https:\/\/gist.github.com\/daveake\/86f7ba32fa8018acd5e5359674a737e5\">here<\/a>.<\/p>\n<p>To receive LoRa transmissions, you need another LoRa device as a receiver, plus suitable software. \u00a0I used my <a href=\"https:\/\/github.com\/daveake\/lora-gateway\">C LoRa Gateway<\/a> code for the receiver:<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-large\" src=\"https:\/\/pbs.twimg.com\/media\/C4OBMIQWMAELSaf.jpg:large\" width=\"1517\" height=\"893\" \/><\/p>\n<h2>Balloon Tracker Program<\/h2>\n<p>So far so easy, and the end goal seemed close; once you have GPS and radio modules working, then you just need a small amount of extra code to format the GPS data as a string, adding a prefix (&#8220;$$&#8221; and the payload ID) and suffix (&#8220;*&#8221; then CRC then a line-feed), and then transmit the result over radio.<\/p>\n<p>However, as soon as I combined the GPS and LoRa code, the result wouldn&#8217;t even compile. \u00a0Remember that compilation happens on the Microbit, and my code was too large for that process:<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"size-large aligncenter\" src=\"https:\/\/pbs.twimg.com\/media\/C4OHi6KWAAE6uiF.jpg:large\" width=\"241\" height=\"152\" \/><\/p>\n<p>Fortunately it wasn&#8217;t much too larger, so I removed some code that wasn&#8217;t strictly necessary (mainly, the code that switches off unused GPS NMEA sentences) and soon the compiler was happy.<\/p>\n<p>The resulting code however was not happy. \u00a0Once the compiler has finished, the resulting bytecode is loaded into the Microbit&#8217;s RAM, which is shares with any data used by the program (variables, stack, temporary work areas). \u00a0The nature of Python is that memory gets allocated all the time, and freed up when necessary (i.e. when there&#8217;s little free memory available), and my program would run for a short while before crashing with an &#8220;out of memory&#8221; error when it tried to allocate more memory than was available. \u00a0This it working before it crashed:<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"size-large aligncenter\" src=\"https:\/\/pbs.twimg.com\/media\/C4PhY6aXAAQTqdY.jpg:large\" width=\"1329\" height=\"532\" \/><\/p>\n<p>So, I had to reduce the memory footprint. \u00a0I&#8217;m used to doing that in C on microcontrollers, but MicroPython needs different techniques. \u00a0For example, C on a micro usually sits in flash memory, which often is less of a limit than is the working data in RAM, so you can sometimes rewrite the code to use less RAM without worrying that the new code uses more code memory. \u00a0Not so for MicroPython, where everything shares RAM. \u00a0So some things I tried actually made the situation (checked by calling gc.free_ram() in the main loop) worse. \u00a0So, for the most part, I managed to increase free RAM by removing code that I didn&#8217;t need. \u00a0Having done so, the program was stable though free memory went up and down cyclically as memory was allocated each loop and then eventually freed up.<\/p>\n<p>Some easy improvements came from removing the code to display GPS satellite count on the LEDs, and specifically importing only the required modules instead of the whole Microbit library. \u00a0The most relevant part of the code turned out to be the part that builds up an NMEA sentence. \u00a0In C you simply allocate enough memory for the longest sentence you need to parse, then place incoming bytes into that memory using a pointer or index, checking of course for buffer overruns. \u00a0In Python, strings are immutable so you can&#8217;t do this, and the temptation then is to do &#8220;string = string + new_character&#8221;. \u00a0Of course, the Python interpreter then allocates memory for the resulting string, marking the old string as &#8220;no longer in use&#8221; so it can be freed up sometime later. \u00a0It&#8217;s pretty easy to end up with lots of unused memory waiting to be freed. \u00a0For now, my NMEA code explicitly frees up memory as each new byte comes in. \u00a0I did briefly change the code to using bytearrays, which are close to what I would do in C, but free memory reduced slightly (I assume the source took more space) so I went back to the original code. \u00a0Longer term, I&#8217;ll ditch NMEA and write code to use the UBX binary protocol instead.<\/p>\n<p>The code has been running continuously now for over 12 hours, and the free-memory figure is solid (measured at the same point each time round the main loop). \u00a0I do need to add the flight-mode code, but that&#8217;s small and\u00a0<em>shouldn&#8217;t<\/em> cause an issue :-). \u00a0If all is well then I hope to fly this (weather-permitting of course) on Sunday.<\/p>\n<p>Finally, here&#8217;s the result of receiving the telemetry on a Python LoRa gateway program that I&#8217;ve been working on lately:<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter size-full wp-image-2026\" src=\"http:\/\/www.daveakerman.com\/wp-content\/uploads\/2017\/02\/skygate_microbit.png\" alt=\"\" width=\"807\" height=\"542\" srcset=\"http:\/\/www.daveakerman.com\/wp-content\/uploads\/2017\/02\/skygate_microbit.png 807w, http:\/\/www.daveakerman.com\/wp-content\/uploads\/2017\/02\/skygate_microbit-300x201.png 300w, http:\/\/www.daveakerman.com\/wp-content\/uploads\/2017\/02\/skygate_microbit-768x516.png 768w\" sizes=\"(max-width: 807px) 100vw, 807px\" \/><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve been meaning to do this for a while, and a short gap between projects gave me some time to try. The Microbit is (yet another) educational SBC, sitting somewhere between the Codebug and a Raspberry Pi. \u00a0Its processor has plenty enough flash memory and RAM to run a basic [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[4],"tags":[],"_links":{"self":[{"href":"http:\/\/www.daveakerman.com\/index.php?rest_route=\/wp\/v2\/posts\/2019"}],"collection":[{"href":"http:\/\/www.daveakerman.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.daveakerman.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.daveakerman.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.daveakerman.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2019"}],"version-history":[{"count":5,"href":"http:\/\/www.daveakerman.com\/index.php?rest_route=\/wp\/v2\/posts\/2019\/revisions"}],"predecessor-version":[{"id":2029,"href":"http:\/\/www.daveakerman.com\/index.php?rest_route=\/wp\/v2\/posts\/2019\/revisions\/2029"}],"wp:attachment":[{"href":"http:\/\/www.daveakerman.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2019"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.daveakerman.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2019"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.daveakerman.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2019"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}