Arduino Library Modifications

Prior to the actual doomsday, we plan to use DOOMSDAY as a race timer for mountain bike races.  To that end we need precision time keeping.  We have a 1 ms accuracy goal relative to an absolute GPS time reference.  The GPS module provides time data in NEMA format as well as a one pulse per second (1pps) reference signal.  When the GPS signal goes out of view, a real time clock chip keeps track of time and provides its own 1 Hertz signal: a 1 Hertz square wave.

In order to sync the 1pps signals to the real time clock square wave, I made some modifications to two libraries: Time, and TinyGPS (by Mikal Hart).  Precision timing is made possible by adding a 1Hz reference to the existing library.  Millisecond accuracy is obtained by keeping track of the last 1 Hz transistion and the 1 Hz duration.  So in addition to the standard year(), month(), day(), hour(), minute(), and second() functions, I added millisecond() which returns an integer between 0 and 999.

Some other functions were added to support the 1Hz reference:

/* TJS: one Hertz interrupt to be called on rising edge of one Hz square wave. 
 *      Used to sync with GPS clock or other 1Hz source to get millisecond time accuracy
 *      trigger is one of LOW, CHANGE, RISING, or FALLING
 */
void set_1Hz_ref(time_t current_time, int interrupt_pin, void(*cb_ptr)(), int trigger);

/*
 * TJS: stop counting ticks.  Used to sync with absolute time.
 */
void pause_1Hz();

/*
 * TJS: start counting ticks.  Used to sync with absolute time.
 */
void unpause_1Hz();

The TinyGPS library also needed to be modified to support precision time synchronization.  The key enabler is a fix notification scheme.  At the heart is a user provided function that gets called when a new fix message arrives.   This function was added to support this:

/*
 * TJS: Add a callback routine to be called when a new fix arrives.
 */
void TinyGPS::add_callback(fix_cb_t fct_ptr);

// Example fix callback signature
void grab_datetime(unsigned long _date,
                   unsigned long _time,
                   long lat,
                   long lon,
                   long alt,
                   unsigned long speed,
                   unsigned long course);

Upgrading to Arduino 1.0

Arduino 1.0 has hit the street.  And with that comes some backward compatibility issues.  These are the ones I needed to address to get ClockTHREE to run on Arduino 1.0.

 

ISSUE #1: “BYTE” keyword is no longer supported, but it is not required with the new Serial.write command.

FIX: Replace Serial.print(val, BYTE); with Serial.write(val);

ISSUE #2: “wprogram.h” not found.  It has been renamed “Arduino.h”

FIX: The release notes includes a handy pre-compiler directive to check of the arduino flavor you are using.

 #if defined(ARDUINO) && ARDUINO >= 100
 #include "Arduino.h"
 #else
 #include "WProgram.h"
 #endif

ISSUE #3: Wire.send, Wire.recieve renamed to Wire.write and Wire.read resp.

FIX: At first I tried writing a couple of macros like FIX 1, but after it took me a long time to discover my mistake, I decided not to be clever here.  I now I just add a pre-compiler conditional for Arduino 1.0.  So you end up wrapping the old code with the check wherever “Wire.send” and “Wire.receive()” where.  Like this (and so on for read/receive).

// Arduino 1.0 compatibility
#if defined(ARDUINO) && ARDUINO >= 100
Wire.write("DATA", 4)
#else
Wire.send("DATA", 4)
#endif
ISSUE #4: NewSoftSerial renamed to SoftwareSerial

FIX: This fix stinks, I don’t know a good way to solve it (suggestions welcome!) Arduino will scan the PDE file for ANY #includes EVEN when precluded by a pre-processor directive. The fix is to comment/uncomment the code for the correct version of Arduino.

For Arduino 1.0:
#include <SoftwareSerial.h>
SoftwareSerial sws(4, 5);
//#include <SoftwareSerial.h>
//SoftwareSerial sws(4, 5);

Syncing Arduino with GPS time

Most people have little need to synchronize clocks to the minute, much less to the millisecond….. but if you do need it, here is how to get millisecond (ms) accuracy in absolute time with Arduino using GPS.

We start with the 1pps signal from the GPS receiver.  The 1pps signal is available from most GPS modules, but double check if you are ordering one for this purpose.  1pps stands for 1 pulse per second.  The pulse is a very short (20 uS = 20/1,000,000 seconds) pulse whose rising edge coincides with the beginning of a second in GPS time.

For some reason, the GPS shield I got from spark fun, did not connect to the 1pps signal even though it had a spot for it.  Checking further showed that only one of the three GPS headers was connected to the 1pps signal.  I red-wired the missing link.

 

I hooked this 1pps signal into digital pin 2 (INT0) so that I could use the hardware interrupt to capture the rising edge of that pulse.  Using this as the absolute 1 second reference, we can measure the drift of the DS3231 real time clock chip.  This is the same chip that is used in the ChronoDot.

I did this by hooking up the 1Hz square wave to digital pin 3 (INT1) and used interrupts to measure time drift DS3231.  My initial test showed it to be loosing about second per year to the GPS time.  Not bad considering they only claim to be accurate to about a minute per year.  Another way to look at the drift is that it will take about 6 hours to loose a milli second (1/1000 of a second).   As long as we can sync with GPS once every 6 hours, we should be able to maintain timing precision and accuracy to a millisecond.

2011 WyoLum Innovation Grant Winners!

And the 2011 WyoLum Innovation grants go to…

Erin Kennedy for her project RoboBrrd and Hunter Scott for the Peregrine Board.  They each will receive $1000.

We had such a hard time limiting the awards to just two winners we ended up with 4 finalists, each receiving $250:

Georg Ottinger — OggStreamer,

Frank Zhao — ReflowToaster,

Jeffrey Stattler — VirtualIntervention,

Travis Dynes — BeeTracker

 

Continue reading

Bits is bits!

So the DOOMSDAY! clock needs to be somewhat weatherproof. With this in mind, we decided to forego any buttons that we’d need to access from the outside of the clock and instead use an infrared remote control that I had laying around from Paralax.

I just now got the ‘duino reading the pulse sequences consistently thanks to some help from the internets.

The first stop was AdaFruit Industries where I picked up a few IR sensors. I know there are a few different vendors out there, but I wanted to make sure that the sensor would work with the code and Ada as a super tutorial that got us up and running quickly.  The sample code in the tutorial continually looks for pulses coming in on the IR pin and measures the “pulse widths” or time durations of the electrical pulses coming from the sensor.  Each button press triggers a train of pulses that are each measured in turn.  The message is determined by the series of pulse widths.

The image below depicts the pulse widths sequentially on a plot for a single button press to illustrate the point.  The blue line shows the on/off durations, the green line just indicates the on durations (or pulse widths).

Where the top image show the raw pulse times, the bottom image indicates weather the each pulse width was above (indicating a binary 1) or below a threshold  (indicating a binary 0) of 1000 uS (1/1000 of a second).  After studying the pulse trains from each button press on my remote, I learned that they all start with the same start and stop sequences with a varying message occurring in the green zone.

So this is enough to get some IR action up and running.  But I didn’t want to tie up the ‘duino checking for pulses when 99.99% of the time, there will be no pulses.  Seems like a waste and when the processor gets busy, the response time will lag.

Interrupts are ideal in these situations.  So much so, it is even worth the hassle of learning how to use them.  They can be tricky to implement and debug, but with the right help, it was not to hard in this case.  The right help came from this page in the Arduino Playground.

Normally, I would use one of the Arduino predefined hardware interrupts on digital pins 2 and 3.  They are very straight forward to use.  In my case however, the hardware interrupt pins were already taken and I had to resort to the PCINT pins.  The ATMEGA328 (heart of Arduino) allows hardware interrupts on each and every pin.  Which brings us to this page on the Playground which shows how.

The idea is to write an interrupt handler that only gets called when a specified event occurs.  In this case, the event is a change on the IR sensor pin.  The rest of the code can be be written without much attention to the interrupt handling.  So if the pin goes from low to high, we start a pulse timer.  When it goes from high to low, we compute the elapsed time from the start of the pulse: the pulse width.  The rest of the interrupt handler checks the pulse width to see if it is above or below the bit threshold and deals with the resulting bit.

What pops out, when a message is sandwiched by a valid START_SEQ and STOP_SEQ, is a 10-bit numerical value which we can use to trigger higher level events and actions.

Here is some test code that makes it happen.