As I mentioned on the GPS podcast, getting the sample sketch was only the first hurdle. The next one was trying to get that sample GPS code incorporated into our master Balloon Sketch. This became a lesson in taking turns.
My first attempt was to copy the sample sketch bits into the appropriate spots in Balloon Sketch, with a minor addition. In addition to the GPS receiver, I’d be writing to the data logger serially. I found information here about running multiple devices serially – the short answer is that you have to access the serial devices – wait for it – serially. To do this, I would “enable” the device that I wanted to read/write from using the “.listen()” method. In addition to writing to the data logger, I was also writing to the standard serial which allows me to see the data coming off the instruments using the serial monitor. I added gpsSerial.listen() and DataLogger.listen() commands, and fired it up.
The GPS receiver was simply returning gibberish.
I decided to simplify a bit by starting with the sample GPS sketch again, and adding in just the data logger pieces. When I tried to pull data off of the GPS receiver and then wrote it to the data logger, I only got gibberish. If I commented out the data logger portions, however, I was able to see good GPS data flowing again. Clearly, the two serial devices were not playing well together.
After thinking about this on and off for a week, and poking around the docs for the GPS receiver a bit, I theorized that I needed to treat the GPS receiver like a firehose.
The sample sketch was written to capture these bytes, save them to a character array until it encountered a carriage return (or it maxed out the array):
(Note: in this diagram, the data looks like it’s coming out of the “firehose” in reverse order, but in fact it’s the order that the data comes off the receiver. It’s saved to the array in the “proper” order.)
A good GPS data stream starts with “$GPRMC”, contains several comma-delimited data points (of which longitude and latitude were two), and finally the carriage return. Then it repeats.
In my sketch, when I had both the GPS receiver and the data logger operating, I would read a few portions of the GPS stream:
And without checking to see if I had a complete GPS data string, I would turn my attention (or rather, the processor’s attention) to the data logger and write out the data I had. The GPS receiver was continuing to feed me data – I just wasn’t listening for a brief period of time:
When I finished writing the data logger entry, I would start listening to the GPS receiver again:
But by that point, I had missed some of the data (the bits in red). Trying to extract latitude and longitude at this point was futile.
My first solution was to rework the sketch to devote all of the processor time to getting a valid GPS coordinate. Once I had that, I would read all of the other instruments to collect those data points, then write everything to the data logger. The next step would be to turn my attention back to the GPS receiver, and wait for the start of the next message to come around (the next “$”). Once I saw that, start recording it as before. Rinse and repeat.
That definitely improved the situation. Now I was getting good GPS coordinates with every write and the pressure/altitude numbers were correct. The temperature sensor, however, was not happy – it was now returning readings of “-1000”.
My next major revision was actually a continuation of the first one:
- Get a good GPS reading. Until I have this, I can’t go on to step 2. I would ignore data coming off the GPS sensor until I saw the “$” character. Then I would capture data in my local array until I hit a carriage return, and process the data as before.
- Get a good temperature reading. Until I have this, I can’t go on to step 3. Since it looks like a “bad” temperature reading was “-1000”, I assumed that a “good” one would be something higher than this.
- Get the pressure reading and calculate the altitude.
- Write everything out.
That revision finally allowed me to get good data off of all of the instruments at the rate of about three times per second. The sensors just needed to learn to take turns. Now that I had the core working, I refactored the sketch a bit to clean up some of the variable and method names.
I also pulled the current timestamp off of the GPS receiver, and added that to the data being written to the data logger (which will help match up data to images when we recover the capsule). The current time comes off the receiver as just another data point, and appears as a 6-digit number (UTC military time).
Overall I think the final sketch reads okay, but it’s not as clean as I was originally planning (Step 1, get all data; Step 2, write all data out). You can find it on GitHub.