a large part of what my high altitude balloon mission computer does, is knowing where it is located. this is done of course by a GPS. I choose he ublox max-m8q as I had good experience using it on the habduino.
one of the weak points of the raspberry pi, is that it only got one serial port. since the radio control already occupied it, i was lucky enough to find the M8Q had an I2C bus as well. if you’re familiar with the I2C protocol, you should know there’s nothing more simple that connecting power, clock and data lines. right ?
well, it turned out to take a lot longer than I expected. right after I finished soldering the tiny SMD part to my PCB (a swearing not to ever try doing it again) I jotted down a simple python script to poll the device and read it’s data. the M8Q warps it serial protocol with the I2C line protocol. since I2C is controlled by the master, if you try to read a byte while the communication buffer is empty, you get back a 0xFF which you need to filter out, and get some 100m Sec of idle time. cool. and it worked! I was ecstatic !
next job was configuring the M8Q to Flight mode instead of pedestrian mode. on our 3rd balloon we lost GPS signal above 18Km, which I thing was bad configuration of the neo-6 GPS. so I read the ublox manual and figured out the right command. and I tried to send it over to find a disappointing quirk. if you google “raspberry pi python i2c” you’ll get plenty of example. ALL of them use the smbus library. which is cool, and usually works. but smbus and i2c are not EXACTLY the same. and one such difference got in my way. it turns out smbus messages are limited to 32 bytes. UBX Commands can be very long. especially switching to flight mode.
in my despair, I’ve checked what dave did on his pi-in-the-sky project. it turns out the he choose not to use the rPi i2c at all and “bit banged” the protocol manually. which is actually cool, and I wish someone would also create such a softserial for the rPi. since my gps was wired to the default i2c pin of the rPi, I turned off the i2c kernel module and adapted his code. but one thing was missing. dave sent his commands, but did not checked for ACK to verify they were received. and after what happened at our last launch, I didn’t want to take any chance. I had to make sure everything is working as planned.
receiving an ACK is not that difficult, but didn’t always happened. or sometimes happened long after I sent the command. probably, the buffer has already full with previous stuff. so I decided to switch to async communication. there’s no way i’m doing it in plain C, so I switched back to python. meanwhile I was doing more research and figured out that it is actually very easy to open and use /dev/i2c directly without using the smbus library.
I used two threads: one thread was polling the bus for incoming data NMEA or UBX and the main thread was sending the Flight Mode command every few seconds until it got the OK flag. (I could have make it even more robust and allow other command, but i’m lazy)
was everything OK now ? well all most. I kept getting corrupted data. a lot of times I’ve not he MSB set on NMEA data which is 32-127 ascii values. i assume this is some kind of timing issue . i’ve tried setting echo options i2c_bcm2708 baudrate=50000 in /etc/modprobe.d/i2c.conf but it did not help (didn’t actually measured if it changed the baudrate ) but as an interim solution I’ve filtered the data in software.
so now I have the GPS, APRS & SSTV up and running, I can write the main command module and we’re good to go.
If you like to see my code you can have a look here (relevant part is in /utils/gps). improvements, comments and other inputs are welcome.