Tuesday 19 June 2012

BlueFlyVario Android App

Android has many quirks but I have a better than expected working app. Together with the prototype bluetooth module it functions better than my first vario from 15 years ago, and I think as well as my current vario. The video at the bottom of this post shows how far I have got. Adding vario functions is just a matter of writing code. Below I mostly describe challenges, but overall I found my first foray into Android Java an easy transition from the J2SE Java desktop environment.

Android version

The latest version of android is ‘Ice Cream Sandwich’. I needed to make some choices what ‘legacy’ devices I will support. Here is a summary of the distribution of devices by Android version. I have three android devices at home, a Froyo (2.2) HTC Aria, a Gingerbread (2.3.3) Samsung Galaxy S, and a ICS (4.0.3) ASUS tablet. Based on what I have, and the distribution of devices, I plan to see if I can choose API level 8. If that does not work then API level 10 is a must.

Android Bluetooth

I started with the Bluetooth Chat sample distributed with the Android SDK. After hacking away for a few hours I was able modify this to get the stream of pressure data arriving just fine. There were a few challenges. The principle challenge was about using BluetoothDevice.createRfcommSocketToServiceRecord(MY_UUID). Unfortunatly this method is a little buggy and causes an error on API level 8 devices. I used the reflection based work around described here and it worked fine.

The Bluetooth connection is still not perfect. I often get a ‘Connection Refused’ on my first attempt, and occasionally on the second attempt. It might be some combination of settings on the RN42. I will need to code in some sort of failsafe.

Graphics

Custom graphics were going to be required to get the look and feel I wanted for the vario. After a little reading I decided to go down the 2D graphics path using a SurfaceView object. Having spent way to many hours in the Java2D libraries this proved pretty easy, in fact, I think it is easier than Java 2D. Even without code optimisation it has ended up being plenty fast enough.

In the video below you can almost see how the desktop vario/alt trace has translated onto Android. I am really happy with this. The drawing is super quick on the ‘old’ HTC Aria. You can see how the trace colour changes depending on the vario value. I have added a little blue dot for the highest vario value in the trace.

What I am aiming for in my reference app is a super thermal hunting machine. I plan to add to the vario/alt trace with a similar trace for location, not on a map, but just graphically. I plan to scribble the same coloured trace (with the blue dot) on a location graph. The idea is to map out the last x seconds of lift/sink to assist with coring thermals. This will need me to read the location (every second or so) and work out wind drift of the trace (based on assuming constant speed). I plan to include this feature in the reference app.

Sound

Making Android go beep was tricky. Android devices have a nasty lag playing sounds. This can be overcome somewhat by using the SoundPool class, but still playing a sound is tricky. I have ended up with a nifty workaround that is acceptable.

To begin with all of the sound stuff needs to happen in a separate thread. This required some synchronization tricks to ensure data being used for the sound (the vario) was not being updated at the same time by the pressure reading / vario calculating thread. I ended up generating a 1s long .ogg file of a 1000 Hz sine wave tone (using Audacity). When beeping is turned on this file just plays in an infinite loop. To adjust the tone the file is sped up or slowed down. This will give tones of 500 Hz to 2000 Hz. If I need tones outside of this I can use other files if needed, but for the moment this range sounds fine.

To adjust the beep I use Thread.pause(ms) for some timing. In each loop I adjust the volume of the tone from 0 to maxVolume to turn the tone on and off. This does not alter the overall device music volume, just the volume of the playing tone. There is negligible delay from setting the volume to maxVolume until the time the tone is heard, compared to ‘play’ which has a slightly noticeable lag. This trick allows the beeping on and off to be quick. The cadence (delays inserted in the Thread.pause(ms)) varies between about 450ms (for 0.2 m/s up) and about 150 ms (for 4.5+ m/s up).

Overall I now have an acceptable beep, although not optimized quite yet. I am not sure if the constantly playing tone is expensive from a battery perspective. I think this will be device dependant, but I don’t think it will be an issue compared to bluetooth and screen use. 

In the future I need to add a sink alarm. I think I might also add in some surprise easter egg sounds for lift above 3m/s!

Battery Life

I have done nothing to preserve battery life yet. I think I can do some things, but overall this app is going to be pretty heavy on the Android device’s battery. If it can last a typical day worth of flying with a few phone calls etc then I will be happy.

Way Ahead

The next steps in app development are:
- Add the location thing.
- Clean up the Bluetooth connection, reconnection, etc.
- Add in ‘start flight’ and flight time recording functionality.
- Add in the user preferences functionality for vario damping, displayed components, units (ft/m), etc.
- Add a few extra altitude displays (height above launch, custom alt based on QNH or a particular reference height.
- Cleaning up code and documenting (comments).

I am aiming for replicating the functions of a basic GPS/vario, adding in my super thermal hunting trace tools. Comp features such as waypoints, routes, etc can wait until future versions. I am aiming to open source this code as soon as I can get the first 10 or so hardware prototypes out. If you are a paraglider pilot and can code Android let me know if you are interested in testing by responding to this thread on paragliding forum.

I am deliberately putting the app coding on hold until I have the next prototype of the BlueFlyVario hardware. That is what will take some time. Components ordered over the internet are starting to arrive…

The video below is a little shaky. Wait until the end of it for some screenshots. The Android devices are an ASUS Transformer tablet and a HTC Aria phone.


Latency and Timing

My experience with latency and timing is worth a blog post. I have now have a working Android app with acceptable timing issues, but not without some pain. The alpha Android app will be described in my next blog post. A few days ago a friend asked me about the project (alight - I offered an explanation). Her immediate question surrounded the latency and what issues I was having. Was the latency acceptable?

Latency

I am going to start by describing the complex pipeline that starts with air pressure, and ends with the Android device displaying something on the screen and going beep.

1. The air pressure and temperature exists at a point in time around the device. Below is a very close up picture of the MS5611 without the protective cap. This is one that I broke. On the left is the actual sensor, the right is the microprocessor circuitry that is part of the sensor. A particular air pressure does something funky to micro diaphragms in the MS5611. I am not quite sure what micro devices bend, or change resistance or capacitance or whatever, but what does happen is that the sensor part of the MS5611 is virtually instantaneously put into a particular state. (I am guessing in pico or nano seconds). 



2. The PIC Micro-controller (operating at 8 MHz) goes through the loop of:
  • 2a. Triggering a temperature sample on the MS5611.
  • 2b. Waiting up to about 9ms for the temperature to be measured internally in the MS5611's microprocessor 4096 times and averaged (at least I think it is averaged and not some other algorithm). It is possible to select a lower oversampling rate and hence be quicker, but the trade off is accuracy. I think it makes more sense to allow that math to be done in the MS5611 microprocessor rather than do it on the PIC.
  • 2c. Then reading the temperature (negligible)
  • 2d. Then triggering a pressure sample (negligible)
  • 2e. Waiting about 9ms again for the MS5611 to do a 4096 oversample of pressure reading for reading.
  • 2f. Then reading the pressure (negligible)
  • 2g. Then triggering a temperature sample (negligible)
  • 2h. Then calculating the pressure from the read temperature and pressure. To do this also takes bunch of  calibration constants which are read from the MS5611 at startup (negligible on the 8Mhz PIC)
  • 2i. Then formatting and sending the pressure characters to the RN42 bluetooth module over UART. I thought that this process would not take much time, but for some time I was using the microchip c++ function sprintf. This is really expensive on the PIC and took heaps of time so I changed to just pushing a sequence of chars to the UART (for those like 'P', 'R' and 'S') and doing a custom int (32 byte unsigned) to char sequence conversion for the pressure (representing the Hex value of the right five nibbles of the 4 byte calculated pressure). This was much quicker, but it still takes time as the PIC to RN42 bluetooth module connection is working at 58k. I guess that this whole print characters thing happens in a few ms. What is important is that I am pretty sure it happens in less than time it takes for the temp measurement on the MS5611. So when we loop back to reading the temperature from the device we will not be waiting for much of the rest of the 9ms.
  • 2j. Then looping back to 2b (I already trigged the temperature at 2g).

In total this takes just less then 20ms. I was able to get it to less than 19 ms (or about 52 Hz) with some tweeking. For reasons described below I slowed this loop down to exactly 20ms. Note that it is about 13 ms from the time of the pressure measurement 2f, to the time it is sent to the RN42 (2i).

3. The RN42 (when established in a bluetooth SPP connection with the Android device), does its thing in some mysterious way. There is this 'bluetooth stack' thing that each character needs to go through, then over the air via the 2.4GHz bluetooth signal, then back through the bluetooth stack on Android. I am not sure how long that takes. From others tests I am guessing about 20 ms. I might do some more tests on this in the future. [probably not – it seems to work ok]

4. The characters then pop out of the bluetooth stack on Android and are read by the Java application code. Here is where things get really unpredictable. I measured the interval between pressure measurements on Android (using System.nanotime(), which I don't really trust but there is nothing better). I found the time intervals to be very erratic. Overall the average time interval is 20ms after I changed it to 50Hz. All pressure measurements are getting through. What I am pretty sure is going on is that the Android threading means that other things, like all that stuff you have going on the background of your PC right now, takes up processor time. At GHz clock speeds the Android device eventually gets around to measuring the data from the bluetooth input stream, sometimes reading a few measurements in a row with less than 1ms in between. My guess is that the average latency here is about 10ms.

5. The vario averaging then adds quite a lot of latency depending on the degree of averaging (damping). With a damping factor of 0.05 at 50Hz it takes about 860ms to reflect 90% of a change. But that is not the latency I am really concerned about. I am more concerned about the latency in 1, 2, 3 and 4.

In total, my guess was that pressure change to pressure available to Java on android latency is about 13 + 20 + 10 ms. So less than 50ms. This should be barely perceptible providing the App can display visually and using audio quickly enough (that story is for the next post).

Timing

Initially I tried spitting out the pressure as quickly as possible from Bluetooth device. I planned to measure the time of the ‘read’ and use this time for the integration of a window of a bunch of pressure measurements. The inconsistency of timing of ‘reads’ of this measurement from Android meant that I was getting screwy results. I tried averaging the pressure time reads, but this was confounded by the few initial measurements that happened at startup. Initialising the vario values worked, but as I tweaked the code on the microchip the pressure intervals would change slightly, screwing up the initialisation.  At the same time I was coding up the display on the android device and it was tricky to relate windows of time to the number of measurements.

The solution to all my timing problems was simple. I implemented a timing loop on the PIC using an interrupt to execute a pressure read and send every 20 ms exactly (50 Hz). The android device just needs to make the same assumption that the pressure measurements are 50 Hz apart, which I now do. Everything with timing is mostly good.

I assume that the internal clock is running exactly at 8MHz. In practice the FRC clock on the PIC is up to 1% or 2% inaccurate. At a particular temperature and operating voltage the clock should be pretty much constant. At 3.0V and 25 degrees Celsius it is most accurate. In practice I do not think that this error is going to matter much. If the vario says 5m/s up when it is really 4.9 m/s I am not sure anyone will care. At some point in the future I could add a crystal to the device to fix this up. Or alternately implement some code on Android to properly measure pressure intervals and add a correction factor. At this stage I am going to do neither.






Thursday 7 June 2012

The MS5611 - a resounding success

I got a few MS5611 samples through a friend in Europe to integrate onto the BlueFlyVario prototype just before I went away a year ago. My initial attempts at soldering on some legs and making dodgy breakout boards failed. I ruined at least one of the samples by melting the protective plastic case. During my time away more people started to use the sensor and I managed to get a few breakout boards from ebay.

To solder the MS5611 onto the PCB breakout board I first put a few very small dabs of solder on the PCB SMD pads. This is easily achieved by first using liquid flux on the pads, then loading up the tip of a standard soldering iron with a lump of molten solder, then just finely touching the molten lump to the pad. The idea is to get a small bit of solder on each pad (with the same amount on each pad!) Next I cleaned the contacts on the MS5611 with flux and wiped it all off - the idea is to remove the oxidation layer. Then I took the PCB and put in on an electric frying pan (skillet). As soon as the pan warmed enough to see the solder melt I put the MS5611 into place with a pair of tweezers. The surface tension from the molten solder held the component in place with a little wiggle of the board. As soon as it was cool I found that I had a perfect SMD solder joint.

I put the associated other components on the breakout board, really only a capacitor and headers, then tested them with the prototype. I had to remove the BMP085 and all of the associated circuitry, then put the breakout board in place. I used the SPI interface functionality rather than I2C as the datasheet said I could expect better noise performance (hence, lower error). It took me a few hours to get everything up and working again. I had to remember how to properly configure the PIC programmer and desktop prototype app. Modifying the PIC 24F code to do SPI ended up being pretty easy, there were a few examples on the net. The first time I properly compiled the program and ran it I got a huge shock, it was working with good, not too noisy, pressure data coming out. I lifted up the prototype vario and my computer went beep.

Some fiddling with the desktop app allowed me to see the altitude graphically and I added in a RMS error to debug the noise. Initially I was getting about 25cm RMS noise with about 50 samples per second. The 50 samples per second actually measures the both the pressure and temperature 50 times a second, then outputs the pressure only. It should be possible to measure the temperature only about 10 times per second, using each temp measurement for about 9 pressure measurements. That would give us about 90Hz for the pressure measurements. I am not sure we need that much...

The prototype was pretty sensitive and it was defiantly an improvement over the BMP085, but I was not happy yet. I added a RF Choke on the V IN line of the MS5611 and the noise went down to about 15cm, although sometimes it floats up if I touch the wrong component on the prototype. I am not sure what the value of the RF Choke is, it was just one that I grabbed from the workbench. The source of the noise could be the linear voltage regulator, the Bluetooth transmitter, or the switching of the PIC microcontroller. It does not really matter, what does matter is that the the noise suppression works really well. I have ordered some ferrite beads for the next prototype. I should get even better noise performance if I filter out noise from the ground plane as well. I don't have an oscilloscope so I can't actually measure what frequencies I am trying to filter and perfectly match the ferrite bead to it. If only I was rich.

Below is a short video of the vario in hand with the prototype desktop app overlayed on it. Note the white altitude display with the vario data (damped) on top of it.



The settings are:
altDamp=0.05 (i.e. 5% of each new measurement is added to the 'current' measurement - see the previous post about the IIR filter to understand what this means)
varioDamp=0.3
varioWindow=50 (about 1 second at the 50 Hz I am measuring at)
vario2Damp=0.05
vario2Window=100 (about 2 seconds)

Next steps:
- Order components for the next round of prototypes (done). I am going to make a couple, with pretty much all SMD components.
- Order PCB prototyping stuff.
- Prepare Eagle circuit diagram and PCB artwork.
- Develop prototype Android app.

Stay tuned, I am back on track. I aim to have a few working SMD prototypes and the prototype Android app by the end of July. Circuit diagrams and code are coming.

Wednesday 6 June 2012

A year of developments

After returning home from almost a year away on a work assignment I now have a little time to continue with my BlueFlyVario project. I have had a lot of success, but that is for the next post. In this post I will provide an update of what has changed over the past year. The bottom line is that the concept I first had some years ago, then started developing in earnest about 18 months ago, remains a worthwhile pursuit.

There has been a little movement in the availability and price of some of my chosen components. The RN42 Bluetooth module has come down in price a little, it is still the cheapest one available and now appears to be more widely used. Microchip has recently bought Roving Networks so I expect that their marketing might will make it even more available in a few months time. The Microchip PIC's are cheaper, as are the batteries and most of the passive components.

The MS5611, the key pressure sensor module I selected, has been used by a range of hobbyists. The Arduino microcopter folks have successfully integrated it. The module is now available in hobby quantities on at least a few specialist websites (http://www.drotek.fr/shop/en/43-ms5611-pressure-barometric-sensor.html for example). You can also get the sensors on breakout boards on ebay occasionally. I got my hands on a few samples from a friend, and ordered got some breakout boards from ebay while I was away. Moreover, there is at least one commercial vario using the MS5611, the Flytepark microvario (http://flytepark.com/Store/Microvario). This is the culmination of Hari Nair's work and I once more congratulate him, not only for this vario, but his ongoing commitment to share his work with an open design.

I am not the only one looking at a bluetooth vario and over the past year others have got similar products to market and further discussed them on forums. The FlyNet vario is one example of something very similar to what I want to build (https://www.asinstrument.ch/pages/home). It is more expensive than I am targeting (over $200) and it seems like the application and design are not open. However, the interface protocol is. I am considering using the same interface protocol as it is very similar to what I am currently using. For me to change will only take a few lines of code. I would add semi regular (once every few seconds) temperature updates, but I am less keen to allow users to change the device name.

Android, the target platform, has continued to get stronger and there are now a wider range of much more capable devices. Importantly, it is easy to pick up a cheap second hand 'old' android phone that should work really well as a front end for the vario. A few recent Android devices now have integrated pressure sensors, but I am unsure if it is possible right now to use these sensors as the basis of a sensitive vario. I think not from my initial research. The sensors are either not sensitive enough (like 30 cm RMS at best) and in many cases the operating system will not return measurements faster than a few Hz. I am aiming for 10cm RMS measurements at 50Hz. There is a discussion about this on pgforum.

Based on all of that I recommenced the hardware prototype development with the aim of integrating the MS5611...