LoRa Repeater

Sometimes it’s handy to have a repeater to extend the range of a radio transmission. The particular usage I have in mind is to be able to receive telemetry from a landed payload that is too far away (or hidden by buildings or geography) to receive directly, but could possibly be received via a repeater up on a mast or flying on a drone. LoRa makes it easy to make a repeater, so that’s what I’ve done here. And to make it more generally useful, the repeater is programmable for frequency etc. via a Windows program, with the configuration stored in the repeater’s EEPROM.


One of these can be made in about an hour if you’re handy with a soldering iron, using these parts:

  • Arduino Mini Pro
  • LoRa module
  • Small 3.7V LiPo battery
  • USB LiPo charger
  • LiPo –> 5V step-up converter

I used a long/slim LiPo but you can use whatever you like. If like me this is just for lifting up on a drone, something small and light is ideal. Even a tiny LiPo will have plenty of capacity for this use.

I connected the charger and step-up converter one side of the LiPo, with the -ve terminals soldered together and to the LiPo. On the +ve side, I placed a 2-pin header between the modules to work as a simple power switch, or you could use a small slide switch. The LiPo +ve wire then goes to the charger +ve terminal. Finally, the +5V output terminals have red/black wires that go down to the Arduino on the other side of the sandwich.

First job on the Arduino Mini Pro is to solder on a programming header. Then connect the +5V from the step-up converter to the Raw pin, and 0V to GND. The Arduino then connects to the LoRa using these connections:

  • GND – GND
  • Vcc – Vcc
  • 4 – RESET
  • 7 – DIO0
  • 8 – NSS
  • 11 – MOSI
  • 12 – MISO
  • 13 – SCK

Finally, solder a suitable length (164mm for 434MHz) wire to the LoRa ANT terminal.


The firmware is Arduino source so you will need an Arduino IDE installed. No extra libraries are used. Get the source from github. Connect the assembled repeater to a suitable programmer and program it.


The configuration program is for Windows only at present. Download the executable from my dropbox.

Connect the repeater to your PC via a USB-serial programmer, then run the configuration program. Select the appropriate COM port in the drop-down box at the top, and the program will automatically connect and display the current (default) configuration:

If you know the PPM offset for your LoRa device, then enter it in the PPM box. What I do to determine this is to set up a LoRa tracker accurately using a precision RF frequency counter, then set up the repeater to the same frequency, note the frequency error and then calculate the PPM figure from that. Once set, it means that you can set your repeater frequencies without having to calculate offsets manually.

“Enable Repeater” does what it says; when checked then the repeater will immediately repeat any telemetry packets that it receives. At present only such packets are repeated (ones beginning with a “$”).

Rx/Tx Settings

The receiver and transmitter are be configured separately so there is no need for them to have the same settings. Generally you just need to set the frequency and mode (pre-determined standard modes that most trackers use); the mode is selected from a drop-down box which has the effect of automatically filling in all of the other settings.

Settings are sent to to the repeater immediately, so you can see their effect immediately in the status section at the bottom, and any received packets on the right. Normally you would do this in the presence of the tracker you wish to repeat, so you can confirm that the tracker is being received OK and ideally with a frequency error less than 1kHz (adjust frequency or PPM till it is).

When everything is OK, click the “Save In EEPROM” button; all settings will then be stored in the Arduino processor’s internal EEPROM memory. You can now disconnect the repeater, and next time it is powered up it will automatically recall the saved settings.

Posted in Weather Balloon | Leave a comment

HAB Explora – Chase App

This is an app for Android that provides the essential functions required when chasing a LoRa high altitude balloon:

  • Chase car upload to Habitat
  • LoRa reception and upload
  • Backup reception of telemetry via Habitat
  • Displays telemetry
  • Displays distance and direction to payload
  • Displays map with balloon and chase positions
  • Option to display driving route on map
  • Function to provide navigation to balloon using external navigation app

The app will be released in the Google Play store soon.

LoRa reception is via an OTG USB connection to a simple receiver comprising a LoRa module plus microprocessor with USB port; this will be available soon in the Uputronics store, or to build one see this article.


Install and start the program. When it starts it will ask for permission to use the device GPS; since this is needed for almost all program functions then it’s best that you agree!

Then connect the LoRa receiver. Android will ask you if you wish to allow the app to use the device (again, you do!). You should also see a dialog asking what program should be associated with the device; choose this app so that it is automatically opened when you connect the LoRa device.

Screen Elements

The app has 3 screen sections. At the top is the main menu with 4 buttons:

  • Payloads – Shows received telemetry for up to 3 payloads
  • Dir – Shows the direction and distance to the selected payload
  • Map – Embedded Google map showing balloon(s) and chase device
  • Settings – Shows the various setup screens

The bottom of the screen is for status.

This shows the LoRa USB status, Habitat status and GPS status. These blocks are colour-coded with black-on-dim-yellow meaning not in use; red text shows error or no data; green shows good recent data. The bar also shows current UTC time from the phone’s GPS.

The central area is for function-specific screens, and initially just shows a splash screen.


Up to 3 payloads can be displayed; if a 4th is heard (via the LoRa receiver) then it will replace whichever of the other 3 was last heard from before the others.

Each displayed payload shows the payload ID, time since last message received, UTC time of that message (as sent by the payload), latitude and longitude, altitude (with maximum altitude in brackets), and ascent/descent rate.

If you do have multiple payloads then you can select between them by touching in the box for the desired payload; the selection will then have a thicker border than the others. Once done, the selected payload will be used on the direction screen and for navigation.

Direction Screen

This screen shows the distance and direction from your location to the latest position received from the payload.

Note that the compass direction is using the current GPS bearing from the phone, which relies on horizontal movement. For this to be accurate you need to be moving, so if you aren’t then walk approx 10-20 metres in a straight line.

Below the compass there are blocks for the payload latitude, longitude and altitude. Below these are buttons for navigation and map directions to the payload:

  • Navigation invokes a navigation app. First time you do this Android will ask you to choose which app you want to use for navigation (e.g. Waze, Google Maps).
  • Off Road is the same, but uses a different Android “intent” which means that Android will ask again for your choice and will remember that choice separately. So you can choose a different app e.g. Back Country Navigator or another OS mapping app.
  • Show Route uses an embedded (i.e. within this app) Google Map to show road directions to the payload.

Map Screen

This shows an embedded Google map:

The map will initially centre on your location, but will then allow you to drag the map around at will. If you wish it to remain centred on your location then touch the “Car” button; if you wish it to centre on the payload then touch the “Payload” button.


There are 3 sections on the settings page:

  • GPS – Controls upload of phone GPS position
  • LoRa USB – Settings for the attached LoRa receiver
  • Habitat – Control telemetry downloads from Habitat

Touch the appropriate button to enter your desired section. Once there, make your adjustments and then touch “Apply” or “Cancel”.

GPS Settings

“Chase Car ID” is what your position will appear as on the spacenear.us map.

“Period” is how many seconds between uploads.

Touch “Enable Upload” (so it is highlighted in yellow) to enable the uploads.

LoRa Settings

“Frequency” is the centre frequency to set the receiver to.

“Mode” is the LoRa mode to set from 0 to 7; most commonly 0 is used for telemetry, and 1 for SSDV with telemetry.

“Receiver Callsign” is used when uploading telemetry and will appear in the listener section against the payload on spacenear.us.

The 2 buttons enable upload of telemetry and SSDV from the tracker.

Habitat Settings

This just has a single button to enable download of telemetry from Habitat; when enabled then the app will check Habitat for any telemetry for the payloads that have been received locally, so that if local reception is lost then it can still be possible to receive position updates.


To see the status of the data sources, touch the status bar on any of the source buttons (USB/Habitat/GPS).


If you want to change which apps are invoked from the Directions screen, go to Android Settings –> Apps, choose the existing app, then choose “Open by default”, then “Clear defaults”.

Posted in Weather Balloon | Leave a comment

HAB Relay Chat

My next flight (depending on wind predictions) will be to try to relay a chat session between 2 remote locations (one in Northern Ireland the other in England) via 2 balloons one launched at each location, with all communications via LoRa transceivers, something that is impossible without relaying because of lack of line-of-sight:

LoRa Possibilities

I’ve previously used LoRa to repeat telemetry between balloons, but all (3) balloons were fairly close to each other having been launched at the same location albeit with 30-60 minute gaps. I’ve also used it to provide a bidirectional data link with a Telnet-like terminal program on the ground and a Telnet server at the balloon. So this flight extends these ideas, greatly increasing the distances involved and having data from the ground relay via both balloons and down to a remote ground location.


As with both of those flights, all trackers and gateways will use the same frequency, taking turns to transmit. For my Telnet flight I used the gateway uplink to tell the tracker when it coulld transmit, but with 2 gateways and 2 trackers that’s not the best plan, so instead (and like the 3-balloon repeating flight) I used Time Division Multiplexing with the trackers using their GPS receiver for timing. Time slots are static and written into the code for each tracker; during non-Tx periods, each tracker listens for packets from other trackers and from the gateways.

I set the frame time to 6 seconds, which conveniently divides exactly into 1 minute and gives an acceptable total transmission time from one gateway to the other and back again, making the system responsive enough for use. The slot allocation is as follows:

  1. Tracker 1 sends short sync packet; gateway 1 responds with uplink
  2. Tracker 1 normal transmission (including uplinked chat text if present)
  3. Tracker 2 repeats Tracker 1 transmission
  4. Tracker 2 sends short sync packet; gateway 2 responds with uplink
  5. Tracker 2 normal transmission (including uplinked chat text if present)
  6. Tracker 1 repeats Tracker 2 transmission

Here’s the system shown in an SDR waterfall:

The yellow packets (lower power) are from my gateways which currently have no aerials connected.

As you can see, the channel utilisation is quite high, and of course it gets higher when chat messages are being sent. The available time slots limit each chat message to 40 characters before signals start to overlap; I’ve set a max of 32 characters for this flight.

Comms Protocol

Messages entered at the terminal program are queued within the program, and then passed to the gateway when it is ready (i.e. when it knows that the previous message has been received at the remote location). The gateway then sends the message to its own balloon, which includes the message in its regular transmission, which is then received and repeated by the remote tracker and then received by the remote gateway. Messages are acknowledged when they have made the full journey, and this acknowledgement than follows the reverse route.

The system copes with any missed packets, retrying until acknowledgement is received.

Chatty Man

Each chat terminal queues up its own messages (marked with a “-” when queued, “*” when in transit), and shows messages received from the other side:

Each gateway broadcasts transmitted and received messages on its local network, where they are received by a “web feeder” program which forwards them to a server program. This web feeder is generic, receiving UDP packets from several ports and forwarding them to the web server. As you can see, that includes packets from my weather station so that I can show local weather data on launch dashboards (for furture flights, not this one):

The server is a small Delphi program running under Ubuntu in an Amazon EC2 instance (I can’t run a server from home as I don’t currently have a public IP address because we’re now using a NATted 4G connection). That web server then feeds the data to browsers running a web dashboard, which looks like this:

You can see a short video of the web app in operation here; note the green/blue highlights showing when normal/repeated transmissions have been received from the trackers, and when the gateways are uplinking:

Note: The web app has changed design since the testing.

Here’s a video showing how the chat works in real time:

Posted in Weather Balloon | Leave a comment

Adding A Strobe Or Buzzer To A Payload

It can sometimes be tricky to find a payload even if you know the co-ordinates – if it’s landed in dense vegetation or high in a tree for example, and of course there are some rare circumstances where you won’t know the exact co-ordinates. For these reasons I’ve added software support for piezo buzzers and LED strobes to my Pi In The Sky software.

Piezo Buzzer

A piezo buzzer is a great way of locating a payload that you cannot see. I used this model from RS Components:

First we need to connect it to the Pi. I suggest that you use a “stacking header” on the Pi so that the pins go through the PITS board and you can then put a solderable pin header on top. To choose appropriate pins to connect the buzzer, refer to the PITS pin allocation table. I chose pin 16 (Wiring Pi pin 4) and pin 14 (0V) as those are free unless you are using an APRS board, which I am not. I used a dual-row right-angle header for a firm connection. Solder the buzzer to the header, fit the header to the Pi (when powered off, unless you’re feeling brave), then test to see it’s working using these commands:

$ gpio mode 4 out
$ gpio write 4 1
$ gpio write 4 0

The buzzer should sound after entering the second line, and then stop after the last line.

Now we can configure the software. Open the configuration file /boot/pisky.txt in the editor of your choice, and add the following lines:


The first line specifies which pin (Wiring Pi numbering scheme) is connected to the buzzer; the second line tells the software to sound the buzzer after descending below the specified altitude. You can omit that second line in which has the altitude will be taken from the existing “high=…” line used for image sizing.

When you start the tracker program you should then see a line like this:

Enabled Piezo Buzzer on pin 4 after descending below 500 metres

Strobe LED

The payload can also announce its position visually, using an LED strobe light as used on R/C aircraft; specifically the Strobon devices such as this one:


This the V1 model; we have tested with this and the V2 model. Both use PWM signal control rather than a simple on/off signal, as they are intended for use in R/C models where spare PWM channels are common. Both devices are incredibly bright and the makers say can be seen from up to 3 miles away at night; I don’t doubt it.

To connect to the Pi, you need to connect the control line, 0V and 5V; I used pin 12 (BCM pin 1) for the control. Note that this time we need to use BCM pin numbers since the PWM signal is controlled by a different I/O library and not WiringPi.

To configure the software, add these lines to /boot/pisky.txt:


When starting the tracker program you should then see a line like this:

Enabled PCM Strobe Light on pin 1 after descending below 2000 metres

The V2 (round) version of the Strobon has slightly different behaviour to the V1 model shown here, as it starts flashing on power-up until it sees a PWM signal, so you will see it flashing until the tracker starts; if it doesn’t stop then check that you specified the correct pin number.

Posted in Weather Balloon | Leave a comment

Double Trouble

For this flight I joined forces with Steve Randall – one of the earliest HAB hobbyists in the UK, and the most prolific launcher; between us we’ve flown well over 200 weather balloons. But experience doesn’t mean that things always go to plan, as we shall see …


The aim of the flight was to try out one of the new range of balloons from Hwoyee, and see how high they can go. They are relatively large balloons, and are double-skinned: to make them fit within standard size filling rooms they have an outer “auxillary” balloon to maintain a spherical shape when inflated, with the main balloon inside of that, joined to a filling valve at a double neck. For this size of balloon, the outer one bursts at around 12km allowing the inner balloon to take over for the rest of the flight.


These balloons are claimed to get as high as 50km, if conditions are right, which is 5km higher than the current amateur record (held by Steve). We didn’t think that altitude was likely this time, nevertheless for my tracker I used a GPS that, unlike the one usually used for HAB, works above 50km. I connected that to a Pi Zero, LoRa radio, Pi camera and 3 AAAs via a boost converter. Steve’s tracker was a new lightweight design of his, with a software mod so that it during advent it sends the highest recent position to transmit.


Filling these large balloons is a challenging affair. First, that’s a lot of hydrogen – around 11 cubic metres – so Steve wore fireproof clothing and we had fire extinguishers and buckets of water to hand. It took 3 cylinders so we had 2 changes during the fill. Finally, that large a balloon makes a big sail, so we erected a tall custom windbreak first.


To make the launch a bit easier, we used a relatively short payload line. That proved to be a mistake. As soon as the balloon was launched, the weight of the inner balloon pulled one side downwards leaving the filling neck, with payloads attached, halfway up one side. Further, the fact that both payloads together only weighed 130g, meant that the balloon had little to persuade it to remain upright. Evidence of the precarious arrangement is clearly seen on some of the live images …


This was my first flight testing my new Android HAB app, which I had running on a new headunit installed in my chase car (lower device here; upper one is my old Pi-based LCARS unit tucked into a storage compartment).

One of the app functions is to speak interesting events over the car stereo, so we had a funny moment when it announced “Flight P T E 1 had been launched” at high volume, shortly after it had been!

Problem 1 – Steve’s Tracker

Everything aside from the alarming turbulence was going swimmingly well – even the ascent rate which was high enough to prevent a sea landing – when the first problem happened – Steve’s tracker stopped updating its altitude, and started to send incorrect latitude and longitude values. We felt this might correct itself during descent, and besides we had a second tracker, so we weren’t overly concerned.

Meanwhile the live images often included the large balloon – both a novelty and a worry as we don’t want the payloads colliding with the balloon as either could get damaged.

Problem 2 – My Tracker

Then my tracker stopped transmitting. Our assumption is that something broke physically due to the turbulence and short payload line, as that tracker has flown before with no issues. So we now had no updates on the flight position. Not good.  Here’s the last position we knew, with a prediction based on the balloon bursting at that point:

Never Give Up, Never Surrender

We did though have one tracker sending something. You can glean a lot just from the radio signal, so I tuned my radio to Steve’s tracker and just listened to the signal. The burst of a balloon is usual easy enough to hear as the payload the to spin during free fall; the radio signal isn’t omnidirectional so the spinning is clearly heard through a radio speaker. I sat listening and waiting, and wrote down the time when I first heard the payload spinning. Woo, a data point!

Record ?

I also had the (errant) telemetry visible on my Android head unit, and I watched that hoping for the error to fix itself. Well, it almost did – the tracker suddenly transmitted the maximum altitude that it had registered during the flight so far. Woo, another data point!

Also woo – it beats Steve’s record!  However, with no corroborating data – i.e. no GPS history of the flight to that point – it’s not one I think we can claim.


We always use the excellent CUSF flight predictor before a flight, to decide what day (and sometimes what time) is best to fly, and then to decide on the best flight path (something which can be adjusted by changing the balloon size, parachute size and gas fill). It has another use too – to help locate otherwise lost flights. To do this, I entered the last position that I knew (from my tracker at around 36km), and the maximum altitude which X2 transmitted. For the ascent rate I started with the average that I saw early, and then adjusted that till the timings matched when I heard the burst. So those data points accurately (I hoped!) profiled the ascent.

Now for the descent. I waited till I lost audio from the tracker, and checked the #highaltitude chat room for when others lost it too.  Mine seemed to be the last anyway, so I used that time. Back on the predictor, I adjusted the landing speed till, at 7.5m/s, the landing time was shortly after the last time I could hear anything. So I now had a prediction to work from, and Julie and I drove there (over 80 miles, and around 100 minutes away) while Steve got on with another launch.  Here’s the final prediction that I made before setting off:


The landing area was west of the A12, so for convenience we aimed for that road then drive North to take us within 500m of the predicted landing point. I fully expected to spend an hour or so drinking round all they local roads on search of a signal, but amazingly we picked up a loud signal as soon as we got near the prediction! We pulled over into a layby and waited for a decode. Unfortunately that was still showing the wrong position. So…


It’s an old technique from when it wasn’t so easy to encode telemetry on a radio signal. All you have to do is use a directional aerial to get a direction to the radio transmitter, then do the same from another location. We did that, and got a position at the far end of the field we parked next to.

Brambles 1

Walking along the side of the field, radio and aerial in hand, I could tell that the signal was coming from somewhere inside dense woodland. Filled with brambles. I ventured in but couldn’t get a definite position, couldn’t see the payload, and was get scratched at every turn. It seemed that the signal was coming from somewhere close to where the trees stopped next to a railway line, so I retreated and tried in the field the other side of the line. Again, triangulation was showing the payload to be near the edge of the trees, but we still couldn’t see it. With skin and clothes torn, and the light fading, we called Steve and decided to wait till the next day.

Prediction Accuracy

Checking on the map at the hotel, I saw that the payload was a mere 250m from the prediction. Let that sink in.  A 250m error, from a point 36km up in the sky, for a flight that reached 45km and travelled 50km horizontally after the last position till it landed. Stunning accuracy (within 0.5%) from the CUSF predictor!

Brambles 2

Steve got to the area at first light, went through pretty much the same process that I did, and with the same results. We may go back when leaves have fallen and it’s potentially easier to see through the dense undergrowth, but for now the payloads are lost. So close yet so far!

Posted in Weather Balloon | 2 Comments

The Compleat Chase Car

Chasing balloons is often the best part of the entire process, but can be challenging if you don’t have the right kit, or it isn’t accessible.  It’s particularly difficult if, as with many of my flights, you’re chasing alone; a laptop isn’t much use when you’re driving!

My previous car was an old Shogun, which served me well but the list of faults was getting rather long so I traded it in for a Hyundai Santa Fe – a bit smaller and not quite as capable off road, but for HAB use with the odd muddy field it will do just fine.  I chose the 5-seat model as it has a huge under-floor compartment in the boot (where the extra row of seats would have been); I use that to store aerials and other equipment:

Here I have:

  • Chase rucksack with tape, ties, knife, hooks, waterproof bag for phone.
  • Yagi aerials for 434 and 868MHz
  • Torches
  • Wellies
  • Spare magmount aerials
  • Saws
  • SLA 12V battery
  • Raspberry Pi LoRa gateway

The LoRa gateway uses a Pi 3 with 434 and 868MHz modules, and connects to the internet via a 4G MyFi device in the cabin.

The gateway aerial cables run underneath the boot, up through the door trim and out at the roof to magmount aerials which attach to washers inside the car when not in use:

Power for the gateway comes from a 37Ah 12V SLA via a 12 –> 5V adapter.  Power to the adapter is switched via a panel mounted in the side of the boot:

The panel includes a voltmeter and dual USB socket, both switched via the first switch in the panel.  The 3rd switch connects power to a 240VAC inverter via a relay next to the SLA.  All supplies are fused, and for convenience the SLA powers 12V cigar lighter sockets in the boot and cabin.

With all this kit in the underfloor compartment, the boot floor is clear and I wanted to keep it that way, so I mounted the various poles (for removing payloads from trees) to the seat backs, using Velcro straps held by metal plates screwed to the seats:

Up front, I fixed my Yaesu 817 radio to the side of the centre console, using adhesive Velcro tape.  The 817 is kept charged from the car 12V supply.  Other connections include the aerial (another magmount), audio via a transformer to prevent earth loop noise, and a USB power adapter:

Now onto the dashboard.  On top is my old Pi-based LCARS device, and below is a Pumpkin double-DIN head unit running Android 7.1.

The Pi device runs a Python application that I wrote a while ago, emulating the Star Trek LCARS displays.  Here it’s streaming video to YouTube:

As for the head unit,  these are essentially Android tablets with WiFi and GPS, FM radio, amplifier, front panel volume control and some handy buttons, SD card slots, and front and rear USB sockets.  This model also has video in (for a rear-view camera and DVD player for example), video out (for seat-back displays), audio in and a steering wheel audio control input.  Buying last year’s model saved a fair amount of money, but didn’t lose any functionality and it’s plenty quick enough in use.  Here’s a short video showing it in use:

I installed apps for offline navigation and OS mapping, plus my own HAB chase app which I intend to release soon.

That app receives data from the LoRa gateway in the boot so it knows where the balloon is, and uses that plus the head unit’s GPS to provide navigation to the balloon once it lands.  I’ll cover the app in more depth in a separate post.

Posted in Weather Balloon | Leave a comment

RTTY Through LoRa Module

Although the current Pi In The Sky boards include an FM transmitter for use with RTTY, there are some reasons for wanting to transmit RTTY through a LoRa module:

  • You can use 1 aerial for RTTY and LoRa, instead of 2, which makes payload design a lot easier
  • Extra RTTY bandwidth
  • You’re making your own tracker and want to avoid the expense of 2 radio transmitters

This article is about using the latest Pi In The Sky software to achieve this.


To transmit RTTY we need to be able to frequency modulate the carrier at a specific rate (e.g. every 20ms for 50 baud).  This timing needs to be accurate.  We could …

  1. Switch the LoRa chip into a mode where it just generates a carrier, and use the RTTY bit stream to set the frequency to one of 2 values every 20ms.
  2. Switch the LoRa chip into a mode where it transmits one of 2 frequencies, with the selection controlled by a DIO pin, and then send the RTTY stream to this pin.
  3. Switch the LoRa chip into FSK (Frequency Shift Keying) mode, with preamble and checksum etc. disabled, and have it send data from a buffer where that data is the RTTY bitstream.

(1) requires accurate timing, which is not so easy with a non-real-time operating system.  I did try this option with a small test program written in Python, and it worked tolerably well at 50 baud, but really isn’t a good option as the timing varies depending on the processor’s workload.

(2) requires an accurately timed bitstream applied to the DIO pin.  This is possible on the Pi using the serial port, but we use that anyway for the standard RTTY radio.  It’s also possible using a software serial port and the Pigpio driver which uses the DMA hardware for timing, but this increases our reliance on a particular external driver and besides, on our LoRa boards the appropriate DIO pin is not connected.

Which leaves us with (3).  There is a difficulty here, which is that the buffer used for FSK is small (64 bytes) and we need to oversample (store the same bit several times) to get the lower baud rates needed for decent range on HAB, but these are just coding challenges.  So this is the option I chose.

Essentially, the code does the following:

  1. Puts the LoRa chip in FSK mode at the desired frequency
  2. Sets the bit rate to a suitable value for the desired baud rate (50 and 300 supported currently).  “Suitable” means a low bit rate (reduces CPU workload refilling the buffer) for which 1 bit in the data results in 1 or more bytes in the FSK buffer (so we don’t need to mess around with individual bits in the buffer, which complicates the code).
  3. Set a buffer warning level so we can quickly sense when to refill the FSK buffer
  4. Tell the chip to transmit
  5. Fill the FSK buffer
  6. Monitor the buffer level and refill as necessary
  7. At the end of the RTTY sentence/packet, allow the buffer to empty

I am indebted to Matt Brejza for the idea, and for providing the code he used to implement this in his tracker, which I then incorporated/mangled to work with the existing PITS software.


First, you need the new version of the Pi In The Sky software (released 26th September 2018), or later versions.

To understand the settings, first take note that PITS has a concept of “radio channels” where a channel is a particular radio transmitter not mode (RTTY or LoRa).  We are using one of the LoRa devices (channels) to transmit RTTY.  So our settings are associated with the particular LoRa module (in CE0 or CE1 position).  Essentially we are overriding the normal LoRa functionality by telling the software to transmitt RTTY as well as or instead of the LoRa packets.

These are the new settings (shown for channel 0)

  • LORA_RTTY_Frequency_0=<RTTY Frequency>.  Without this, RTTY will use the same frequency as LoRa.  I recommend that you keep the frequencies apart so that your RTTY receiving software does not try to track the LoRa trransmissions.
  • LORA_RTTY_Baud_0=<baud rate>.  Choose 50 (better range) or 300 (faster, allows for SSDV, easier for dl-fldigi to lock to).
  • LORA_RTTY_Shift_0=<carrier shift in Hz>.  The carrier shift must be numerically greater than the baud rate.  Note that the LoRa chip steps in multiples of 30.5Hz.
  • LORA_RTTY_Count_0=<count>.  This is how many RTTY packets are sent one after the other before transmitting any LoRa packets.  2 is recommended in case the RTTY decoder misses the start of the first packet.
  • LORA_RTTY_Every_0=<count>.  This is how many LoRa packets are sent one after the other before transmitting any RTTY packets.  Set to zero to disable LoRa (and only send RTTY).
  • LORA_RTTY_Preamble_0=<bits>.  Sets the length of preamble (constant carrier) before sending RTTY data.  Default is 8 and seems to be plenty.





  • Only 50 baud and 300 baud are currently supported.  This may change in future releases.
  • If you choose to interleave RTTY and LoRa, then any SSDV packets are only sent out over LoRa.
  • If you want to transmit SSDV over RTTY, then you need to disable LoRa transmissions on that module, and use 300 baud.
  • You cannot have separate payload IDs for RTTY and LoRa on the same module.


Posted in Weather Balloon | 1 Comment

Making a Pi Zero GSM/GPS HAB Backup Tracker

This is an update of a previous post, but post-flight (so I know that it works!) and with instructions on how to make your own tracker, and your own gateway to upload to the live HAB map.


GSM-based trackers are quite rightly frowned upon for HAB tracking, mainly because they only work at low altitudes (within range of a mobile phone tower, which aim the signal generally downwards).  So they don’t provide tracking throughout a flight, which is a problem as then you don’t know where the payload is until it lands.

If you’re lucky.

There are 2 problems here – one is that GSM coverage isn’t 100%, and the other is that the popular GSM trackers don’t seem to like high altitudes.  I don’t know if they get confused, or they don’t like the cold, but I’ve tried these things several times and only had one work once.

A GSM/GPS tracker that actually works would be useful though, as a backup to a main tracker.  Having had little success with commercial offerings, I thought I’d make one.  I found a Waveshare model that uses the SIM868 GSM/GPS module, plus supporting electronics on a Pi Zero HAT.  So that plus a Pi Zero and suitable power supply would make a fairly small backup tracker.

The device supports GSM (calls, texts) and GPRS (2G, i.e. slow data).  It also has a GPS receiver.  It seemed attractive to use GPRS to provide internet access (via PPP), but that would lock out the single serial port thus making GPS unavailable.  So I decided to just send SMS from the device instead, using a script that gets the GPS position, then builds and sends an SMS containing that position.  I wrote this in Python using the PyGSM library, which makes things very easy (generally no need to mess around with AT commands).  PyGSM doesn’t know about the SIM868 GPS functions however, but it was simple to add those.  So my test script requests and parses the GPS position, then formulates a text message and ends it to my mobile phone:

Live Map

It would also be useful to have the balloon position automatically uploaded to the live map, so I decided to have the device send a second SMS but this time to a gateway based at home.  This gateway is another Pi with a USB 3G modem attached.  I used the same library, but a different script to poll for new messages, determine whether an incoming message is of the correct format, and if so build a UKHAS telemetry sentence, finally uploading it to habhub for the live map:

Hardware Build

For the tracker, mount the Waveshare GSM/GPS board on a suitable Pi (the Pi Zero is ideal – less power and weight).

For the gateway, use a Pi B+ (V2 or 3 or whatever you have handy), and connect a USB modem (e.g. Huawei E173, which is very common and works well on the Pi).

You can use the software without a gateway if you wish, in which case you will only have texts sent to a smartphone and not uploaded to the live HAB map.

Software Installation

Use the same instructions for both tracker and gateway.  Build a bootable SD card in the usual way, using Raspbian Lite.

Next install git other dependencies:

sudo apt install git apt-get python-setuptools python-pip wiringpi

Install the pygsm library:

git clone https://github.com/adammck/pygsm.git
cd pygsm
python setup.py install

and other Python dependencies:

sudo pip install crcmod

Install the tracker software:

cd ~
git clone https://github.com/daveake/GSMTracker.git



First, start the gateway software:

cd ~/GSMTracker
python gateway.py

Assuming the 3G modem is connected and working, with a valid SIM card, you should see something like this:

Modem details ...
Manufacturer = huawei
Model = E173

Phone number = +4476543210

Waiting for messages ...

Take a note of the phone number.

Payload Document

For the tracker to appear on the UKHAS map, it needs to have a payload document.  Create one using the habhub page and with these fields:

Set the payload ID to something meaningful (but please not “GSM” as that’s what I use!) and set the checksum type to “crc16-ccitt”.


First, start the GSM/GPS module by pressing the button on the side.

Now run the tracker program, using that phone number and also the number of your smartphone.  The format is:

python gsmtrack.py <payload_ID> <phone_number> [gateway_number]

For example:

python gsmtrack.py GSM 07987654321 07876543210

where the “payload_ID” must exactly match the ID you used in the payload document; the phone number is that for your smartphone, and the optional gateway number is that of your gateway to upload to the map.  You should see something like this:

Texts will be sent to mobile phone 07987654321
Texts will be sent to gateway number 07876543210

Modem details ...
Manufacturer = SIMCOM_Ltd
Model = SIMCOM_SIM868

Switching GPS on ...
Position: 16:49:54, 52.12345, -1.23456, 155.611
Send because of timeout
Send because of horizontal movement
Send because of vertical movement
Sending to mobile 07987654321: GSM position: 16:49:54, 51.1....
Sending text to gateway
Sending to gateway 07876543210: HAB:GSM,1,16:49:54,51.1...
Position: 16:50:05, 51.12335, -1.23458, 153.100


For the tracker, you should have it start up automatically.  This should include automatically starting the GSM/GPS device as it does not start up when power is applied.  Earlier we did that by pressing the button on the board, but we can automate that in a script:

cd /home/pi/GSMTracker

gpio mode 7 output
gpio write 7 0
sleep 1
gpio write 7 1
gpio mode 7 input
sleep 5

while :
    python gsmtrack.py GSM 07987654321 07876543210
    sleep 5

Start that when Raspbian starts, using your preferred startup method.


For flight, package the tracker in a small foam polystyrene container, using a suitable power source.  I used a powerbank that accepts AA cells, populated with Energizer Lithiums; this is the safest option.  Remember to connect the GSM and GPS aerials, and have the latter at the top of the payload.

The tracker will send texts to your phone and gateway when it first gets a position, every 10 minutes thereafter, or more often if it detects horizontal or vertical movement.  The update rates are in the code and can be easily changed.  It will only attempt to send out texts when below 2000m.

Posted in Weather Balloon | 5 Comments

Pi Zero GPS/GSM Tracker and Habitat Gateway

GSM-based trackers are quite rightly frowned upon for HAB tracking, mainly because they only work at low altitudes (within range of a mobile phone tower, which aim the signal generally downwards).  So they don’t provide tracking throughout a flight, which is a problem as then you don’t know where the payload is until it lands.

If you’re lucky.

There are 2 problems here – one is that GSM coverage isn’t 100%, and the other is that the popular GSM trackers don’t seem to like high altitudes.  I don’t know if they get confused, or they don’t like the cold, but I’ve tried these things several times and only had one work once.

A GSM/GPS tracker that actually works would be useful though, as a backup to a main tracker.  Having had little success with commercial offerings, I thought I’d make one.  I found a model that uses the SIM868 GSM/GPS module, plus supporting electronics on a Pi Zero HAT.  So that plus a Pi Zero and suitable power supply would make a fairly small backup tracker, and maybe even one that works.

The device supports GSM (calls, texts) and GPRS (2G, i.e. slow data).  It also has a GPS receiver.  It seemed attractive to use GPRS to provide internet access (via PPP), but that would lock out the single serial port thus making GPS unavailable.  So I decided to just send SMS from the device instead, using a script that gets the GPS position, then builds and sends an SMS containing that position.  I wrote this in Python using the PyGSM library, which makes things very easy (generally no need to mess around with AT commands).  PyGSM doesn’t know about the SIM868 GPS functions however, but it was simple to add those.  So my test script requests and parses the GPS position, then formulates a text message and ends it to my mobile phone:

It would also be useful to have the balloon position automatically uploaded to the live map, so I decided to have the device send a second SMS but this time to a gateway based at home.  This gateway is another Pi with a USB 3G modem attached.  I used the same library, but a different script to poll for new messages, determine whether an incoming message is of the correct format, and if so build a UKHAS telemetry sentence, finally uploading it to habhub for the live map:

UPDATE: Software now uploaded to github: https://github.com/daveake/GSMTracker

Note: Not tested in flight yet so I don’t know if the software and/or hardware chosen will work or not, so user beware!!

Posted in Weather Balloon | Leave a comment

Pi Zero W Streaming Dashcam

Tidying my office a few days ago, I came across some car reversing monitors that I used to use as cheap Pi displays for use in the chase car, to show the distance and direction to the payload; these days I use the official Pi touchscreen as it’s a lot better for that application.  One of the monitors is a flip-up model, and I wondered how much space there was inside.  I use the Pi Zero a lot for balloon trackers, as it’s small and light compared to other Pi models, but perhaps one could fit one inside the base to make a smart dashcam – one that can stream my balloon chases to Youtube as well as record to SD.

About the same time, Michael Horne (author of the excellent Pi Pod blog), posted a picture of a similar-looking model on Twitter, asking how to power it from 5V.  That’s the opposite of what I wanted to do (power the Pi Zero from the 5V rail inside the monitor) but I felt I might be able to help so I opened up my unit to find where the 5V could be tapped.  As it turned out, Michael’s unit had a very different PCB to mine, but the seed was sewn so I decided to start building my dashcam.

Pi Zero to Monitor

First job was to connect the the display to a Pi Zero W (W because I want to be able to stream the camera video). This requires the 5V and GND lines on the GPIO pins, plus the composite video output pin, to be wired to their counterparts in the monitor.  Once I’d used the correct video pin this worked without issue!

I don’t know how much spare current capacity the display has on the 5V rail, but it dropped slightly from 5V to 4.9V which is OK.  The Pi Zero booted and ran continuously overnight with no issues and with nothing on the display PCB getting hot.

I connected the Pi Zero to my LAN via a USB LAN adapter, ssh’d to it, then set the video aspect ratio to match the monitor (16:9).


The full set of options is:

I also updated/upgraded Raspbian, and set up the WiFi.


Next steps were to enable and connect the camera, and to install ffmpeg, which is what I use to stream to YouTube.  I used these instructions to install the library:

cd /usr/src
git clone git://git.videolan.org/x264
cd x264
./configure --host=arm-unknown-linux-gnueabi --enable-static --disable-opencl
sudo make install

and then ffmpeg.  This takes several hours to build, so it’s a good time to find something else to do!

cd /usr/src
git clone git://source.ffmpeg.org/ffmpeg.git
cd ffmpeg/
sudo ./configure --arch=armel --target-os=linux --enable-gpl --enable-libx264 --enable-nonfree

Aspect Ratio

I then tested the video streaming to YouTube with a command like this:

raspivid -o - -t 0 -w 640 -h 360 -fps 25 -b 500000 -g 50 | ffmpeg -re -ar 44100 -ac 2 -acodec pcm_s16le -f s16le -ac 2 -i /dev/zero -f h264 -i - -vcodec copy -acodec aac -ab 128k -g 50 -strict experimental -f flv rtmp://a.rtmp.youtube.com/live2/<stream ID>

which worked to Youtube, however the preview displayed on the monitor was distorted.  I thought that this was to do with Raspbian not correctly applying the screen resolution, but no matter what I did to fix that (specifying the resolution explicitly in config.txt, or specifying the preview window dimensions) fixed it.  Eventually I concluded that the issue was within raspivid, and then I soon found a very relevant forum post, which explained how to modify raspivid:

git clone https://github.com/raspberrypi/userland.git
cd userland

Then add these lines near line 116 of RaspiPreview.c:

param.noaspect= MMAL_TRUE;

then rebuild.  After following these steps, the problem was gone!


With the base plate removed, I threaded the flat camera cable up through the back of the base, behind the support that goes up to the top of the display, connected the camera and fixed it in position with Sugru:

I then added a piece of black duct tape covered the cable to stop it snagging and make it look tidy.


The Pi Zero has 3 wires connected – 5V, 0V and video, which on my monitor go to a convenient electrolytic capacitor and the back of a PCB socket.  Finally, a switch is mounted near the front of the monitor’s base, and connected to a GPIO pin and GND:

Everything was then insulated with duct tape before screwing on the metal base.


I wanted the dashcam to work in one of 2 modes – to record as a dashcam normally would, and to also live stream to YouTube (via the WiFi connection to a phone or MyFi device, for example).  So I wrote a small script that switches modes according to the position of a switch connected to a GPIO pin.  On startup, or when the switch position changes, the script runs the appropriate shell command for that mode.  For regular dashcam recording, that’s a simple raspivid command; for streaming it pipes the raspivid output through ffmpeg (see command above).  At present I’m not recording the video, so I need to do that using rotating file names, over-writing old files before the SD card fills up, and recording at a high resolution but streaming at a lower resolution.



Posted in Weather Balloon | 2 Comments