Wednesday, 11 May 2016

Nearmiss-o-meter, The Difficult Second Album

It's been a little while since the last update. Who'd have thought product development could take so long?

Snorkel Design

The original design.
I've been chasing down a few minor frustrations with the first complete version of the Nearmiss-o-meter.

The first was caused by the design of the snorkel, causing a resonance similar to blowing across the top of a bottle. This in turn 'blinded' the sonar in gusty conditions.

A redesign for the original box, similar to the original cardboard concept resolved this and I have now also redesigned the case to allow interchangeable snorkels of different lengths.

Only measures 6cm...?
It works...
However, a very minor change to the snorkel throat for the new box introduced an echo that meant the sonar read only 6cm!

Spot the difference.


GPS Checksum Errors

The second major issue was a little harder to track down. Periodically, the GPS appeared to stop reporting. A bit of debugging later, and this was tracked down to TinyGPS complaining about an invalid checksum. Most GPS devices (such as the uBlox) send out information as NMEA sentences, which includes a checksum at the end. Both the uBlox and the TinyGPS library are very mature and when I ran them in isolate test, I could not replicate the error. So the bug was very likely in my implementation.

Intermittent issues are always tricky. The key to squashing any software bug is to be able to replicate it reliably, but the the GPS lockups seemed to be random. It would track perfectly for long periods, then stop for 20 seconds, then continue normally, stop, continue etc. Very frustrating.

After eliminating any issues with my code, I started thinking about timing and buffers. The uBlox delivers all the NMEA sentences in one burst. These sentences are only a single line, each of less that 80 characters, but they are all delivered at once, on the epoch of each second (i.e. 1Hz) That's not a lot of data to consume for your average PC, but the Arduino has a default serial buffer of just 64 bytes.

The initial fix was to reduced the number of NMEA messages to just the bare minimum and counter intuitively use a slower baud rate. This seemed to help, but did not solve the problem completely. If the Arduino 'loop' strayed out of sync (i.e. was not ready to read the buffer at the epoch) then the serial buffer would overflow and TinyGPS would not have a valid checksum.

The next step was to investigate increasing the serial buffer. I wanted to avoid this as it cannot be done in the sketch and is different for every type of board, which complicates other peoples setup but it had to be done.

Board Upgrade

In the process of trying to debug all this, I switched from the 32u4 version of the Adafruit Feather moving up to the M0 - a whole 256Kb! The 32Kb limit (actually 28Kb of code)meant I was spending much of my time reducing the size of the code rather than building the functionality I wanted. The Feather M0 is physically identical (thank you Adafruit) but quite different to code for. Most Arduino libraries will run fine but crucially, not the SoftwareSerial. Oh Pooh, said Piglet. We need that for the sonar. Don't worry said Lady Ada, use SERCOM! If you really want to get down & dirty, read this excellent tutorial on muxing and serial SERCOM. I cannot praise Adafruit enough for their documentation.

Serial Sonar Modulation

Moving swiftly on, I then needed to address the serial sonar library. If no object was detected within 8 metres, the sonar firmware would take almost a 10th of a second to respond to a single 'ping'. This is not good when you're attempting to read the median of five pings, five times a second. No amount of messaging would persuade it to abort mid ping, so I have implemented a 'modulating' median ping. The library will do as many reads as it can (up to 5) within a given time frame and then return the median. Sorted.

New stuff

Moving to the M0 allowed me to build in the following functionality:

  • Greater 'accuracy' for lon/lat recording using the TinyGPS++ library. See this excellent reply for further information. We are now recording 6 decimal places - this does not mean the lon/lat will be accurate to 11cm, but is does mean the trace will be smoother.
  • A config.txt file on the SD card to allow end users to change the Nearmiss-o-meter behaviour without having to recompile and reload to the Arduino. e.g. sonar offset, timezone etc.
  • Date/time stamps for files. It didn't bother me too much, but seemed very peculiar to see files dated 01-01-1970... We are still limited to 8.3 file names, but the config.txt above allows both the filename and the timestamp to be in local time rather than GMT.

Disable vs Isolate

For the first version, I simply isolated the battery with a switch. This is the 'better safe than sorry' approach, but it means you would have to switch on the nearmiss-o-meter in order to charge it. Not very user friendly. Adafruit have implemented an unintuitively named ENable pin. If this pin is grounded (it is held high internally), the 3v3 regulator is disabled thereby shutting down the processor and the peripherals. A bit of measuring of the 'quiescent current' with a friends highly sensitive meter and a bit of maths told us the battery would last more than a month in standby mode. I am still chasing down an oddity whereby I can read 0.8 volts between 3v3 and GND when in disable mode...

Other stuff

I've also created a small handlebar button comprising three components (and took a surprising amount of time to design...). This makes it much easier to start/stop recording and 'tag' near misses.

This now has just two LED (red for GPS and green for recording) as the multiple colours did not aid readability. The blue nearmiss/testing LED has moved to shine out of the snorkel along with the light sensor to auto dim the LEDs.

So it is still a work in progress... I hope to have a PCB design ready to send off soon & then perhaps make a couple of boxes for interested parties/patrons to test :-)

Update #1

The Arduino code & Eagle (Gerber) files etc will be published on Github.

The logic behind creating a couple of test units is to ensure other people don't waste their time/money/efforts on something that doesn't work as expected. An example of this is the use of various pins on the Arduino - I've learnt that some can do PWM (for dimming LEDs), others can not. The same for the SERCOM pins.

The second reason for the test units is to prove the usability of the design (developers of software and or physical products are the last people you should choose to do testing) and also to start to understand how the data can be collected/collated/validated etc.