Wednesday, February 16, 2011

A custom gyro compass (Phase 1)

I have completed Phase 1 of my project, and I am very impressed by the performance of the MicroMag3 magnetometer. No hysteresis, spectacular real-time responsiveness: it looks like the motion-corrected part of the project (Phase 3) will not be necessary with this technology.

Here is the set-up used for these preliminary tests. The magnetometer on the breadboard is connected to a MAVRIC-IIB controller through the SPI bus, plus two other control lines as described in the datasheet. The microcontroller sends the calculated heading to a computer running Hyperterminal via a serial-to-USB converter.

When measuring only 2 axes on the horizontal plane with a resolution better than 0.1 degree, a sampling rate of 14.25 Hz can be achieved. Higher sampling rates could be used at the expense of the resolution. 

Here is the output produced when the breadboard is quickly snapped to a new angle every second or so.

The responsiveness is so sharp than you can even calculate the time taken during the quick rotation: it is around 3 time steps or 0.2 second. In a practical compass application, there is no need for a gyro: the rate of turn can be calculated directly from the magnetometer output.

Now some design considerations.

The objective is to get a resolution of 0.1 degree, with a 10 Hz update rate. In my location, the horizontal magnetic field is 17.7 microteslas (uT), which means that the resolution of the magnetometer should be 17.7 * 0.1 / 90.0 = 0.0197 uT. The MicroMag3 can achieve a resolution of 0.015 uT, but at the expense of an average sampling time of around 35 ms for each of the 3 axis. As it can measure only 1 axis at a time, this means a total sampling time of 105 ms, or 9.5 Hz at best. This does not leave time to add the accelerometer and tilt compensation calculations. To keep with the initial objective of 10 Hz, one would need 2 magnetometers working in parallel. In fact, I have decided to use 3 MicroMag3 in parallel for the final design, to insure that the measurements of each of the 3 axis of the moving compass will start exactly at the same time. It’s definitely not an economical or an elegant solution, but sometimes you have to use some brute force.

In this preliminary test, the Micromag3 was operated at 5 V, but it is optimized for an operation at 3.0 V. In the final design, I will use a microprocessor that can operate at 3 V to get the best accuracy, and to avoid a LOT of logic level conversions between the microprocessor and the 3 magnetometers. Another interesting characteristic of the Micromag3 is that you can calibrate all three axis with the official published magnetic field data for your location.

UPDATE :  the finished compass is described in this post.

Monday, February 14, 2011

Leeway calibration (Part 3)

I propose here an exercise to assess the practical effects of 2 corrections described in previous posts:
  • correction of apparent wind angle vs heel
  • correction for leeway
We will see the results displayed by 3 types of instrumentation system, for a sailboat on a tack in the following conditions (assuming no upwash, and no wind shear).

System  A : basic system, no correction
System B :  AWA corrected for heel
System C : AWA corrected for heel, and results corrected for leeway

System C is the only one reporting correct values in these conditions.

The following table presents the data that would be displayed by each of these systems.

System ASystem BSystem C
No correctionAWA correctedlike B + corrected
for heelfor leeway
(other tack)

We see that the most volatile figure is the true wind angle (TWA), and by consequence the wind direction (WDIR). We also see that systems without correction make you believe that your boat is pointing like a champion. It is possible to retrieve the correct TWA by taking the average WDIR over the 2 tacks and back-calculating the TWA. This is called ‘dewiggling’ and the poor upwash is usually identified as the responsible, even if it has often nothing to do with that. 

Wednesday, February 9, 2011

Leeway calibration (Part 2)

In the previous post, I have presented a method to calibrate the leeway of a sailboat. Here, I present the details of the required calculations, in the form of a C-language routine. Beware that if you want to program this in Excel, the Excel ATAN2 function needs the arguments in reverse order : (x, y) instead of (y,x).

#define PI 3.14159265
#define DEG_TO_RAD ((double)(PI/180.0))
#define RAD_TO_DEG ((double) (180.0/PI))

// inputs from downwind leg
double sog2;  // GPS SOG of downwind leg
double cogm2;  // GPS COG (corrected to magnetic) of downwind leg
double stw2;  // measured boat speed (also real STW) of downwind leg
double heading2; // heading of downwing leg

// inputs from upwind leg
double sog1;  // GPS SOG of upwind leg
double cogm1;  // GPS COG (corrected to magnetic) of upwind leg
double heading1; // heading of upwind leg

// outputs
double leeway;  // leeway angle of upwind leg;
double soc;   // speed of current (common to both legs)
double doc;   // direction of current (common to both legs)
double stw1;  // real speed through water of upwind leg;
double dir_stw1;    // direction of stw1 in compass coordinates

// intermediate values
double cogm2_rad; // cogm2 in radians in cartesian coordinates
double sog2x;  // horizontal component of sog2 in cartesian coordinates
double sog2y;  // vertical component of sog2 in cartesian coordinates
double heading2_rad; // heading2 in radians in cartesian coordinates
double stw2x;  // horizontal component of stw2 in cartesian coordinates
double stw2y;  // vertical component of stw2 in cartesian coordinates
double socx;  // horizontal component of soc in cartesian coordinates
double socy;  // vertical component of soc in cartesian coordinates
double doc_rad;  // doc in radians in cartesian coordinates
double cogm1_rad; // cogm1 in radians in cartesian coordinates
double sog1x;  // horizontal component of sog1 in cartesian coordinates
double sog1y;  // vertical component of sog1 in cartesian coordinates
double stw1x;  // horizontal component of stw1 in cartesian coordinates
double stw1y;  // vertical component of stw1 in cartesian coordinates
double dir_stw1_rad // direction of stw1 in radians in cartesian coordinates

cogm2_rad = (90.0 - cogm2) * DEG_TO_RAD;
sog2x = sog2 * cos(cogm2_rad);
sog2y = sog2 * sin(cogm2_rad);

heading2_rad = (90.0 - heading2) * DEG_TO_RAD;
stw2x = stw2 * cos(heading2_rad);
stw2y = stw2 * sin(heading2_rad);

socx = sog2x - stw2x;
socy = sog2y - stw2y;

/******* this section is optional *************
soc = sqrt(socx * socx + socy * socy); 

doc_rad = atan2(socy, socx);
if(isnan(doc_rad))   // singularity
 if(socy < 0.0)
  doc = 180.0;
 else doc = 0.0;
 doc = 90.0 - doc_rad * RAD_TO_DEG;
 if(doc < 0.0)
  doc += 360.0;
 else if(doc >= 360.0)
  doc -= 360.0;

cogm1_rad = (90.0 - cogm1) * DEG_TO_RAD;
sog1x = sog1 * cos(cogm1_rad);
sog1y = sog1 * sin(cogm1_rad);

stw1x = sog1x - socx;
stw1y = sog1y - socy;

/******* this section is optional *************
stw1 = sqrt(stw1x * stw1x + stw1y * stw1y);

dir_stw1_rad = atan2(stw1y, stw1x);
if(isnan(dir_stw1_rad))   // singularity
 if(stw1y < 0.0)
  dir_stw1 = 180.0;
 else dir_stw1 = 0.0;
 dir_stw1 = 90.0 - dir_stw1_rad * RAD_TO_DEG;
 if(dir_stw1 < 0.0)
  dir_stw1 += 360.0;
 else if(dir_stw1 >= 360.0)
  dir_stw1 -= 360.0;

leeway = dir_stw1 - heading1;

Monday, February 7, 2011

Leeway calibration

Leeway calculations are usually based on the following formula:

               leeway  =  K * heel / speed2
where leeway and heel are in degrees and the boat speed is in knots. The only problem is to find the constant K for your boat. Different methods have been proposed that all present practical difficulties and do not lead to accurate results.

Here is a method that relies on the capacity of this system to record several concurrent values in real time, and most importantly, on a precise calibration of the gyro compass.

It is also based on a trial run where you sail on a tack with a sensible heel angle, while recording: measured boat speed, heel angle, heading, SOG and COG. When you have reached stable conditions for one or two minutes, you turn around, set the sails wing on wing, and go straight downwind until the conditions have stabilized for another minute or two. This last step is necessary to measure the effect of the current, as the leeway angle will then be zero.

First part

Second part

In the second part of the trial test, we have measured the GPS speed over ground (SOG2), the GPS course over ground (COG2), and the measured boat speed that is also the real speed through water (STW2) as there is no leeway. From these values, we calculate the speed of the current (SOC) and its direction (DOC). We will need the SOC and DOC to calculate the leeway from the results of the first part.

During the first part of the test (tack) , it is important to note that the measured boat speed is NOT the real speed through water. The speed sensor is aligned with the boat centerline, and what it measures is the component of the real STW along the heading axis (the dashed arrow in the figure). In order to calculate the leeway, we will need first to calculate the direction of the real STW arrow (the solid blue arrow). It can be calculated by adding the SOG1/COGm1 green arrow with the negative SOC/DOC arrow. Once we have the direction of the STW, the leeway angle is simply the difference between it and the compass heading.  These calculations involve some non-trivial trigonometry, and I will present in a future post the exact equations for that.

I use the Airmar speed sensor model without the fins on each side of the paddlewheel. I consider that the fins are prone to bring local disturbances that are detrimental to the measurement accuracy.

Once we have the leeway angle from the test, we can calculate the constant K, using the boat speed and the heel angle from the first part of the test.

K = leeway  * speed2 / heel

Friday, February 4, 2011

Corrections to the apparent wind angle

In a previous post, we have been able to calibrate the apparent wind angle (AWA) relative to the axis of the sensor itself. However, if the sensor axis is not aligned with the centerline of the boat (remember that we are seeking a resolution of 0.1 degree), we have to measure this offset. Here how it is done with this system.

We go on the water on a (nearly) windless day, and we keep motoring straight ahead against the wind (if there is some). During a period of say 30 seconds, we record the apparent wind angle. After that, we take the average (this is about 300 data points), and this is the offset that we will have to substract from now on:

awa_corrected_for_offset (awa_coff)  = awa_measured - offset

We also have the make a correction when the boat is heeling. Because the sensor is not on a 3-axis swivel, there is a purely geometric error induced when the AWA is not exactly a multiple of 90 degrees (0, 90, +-180, -90). For an explanation of the phenomenon and the required correction, see page 8 of the following document:
So we have to apply this second correction:
awa_corrected_for_heel  = atan { tan(awa_coff) / cos(heel) }
The following figure presents the error in degrees at sailing points between 0 and 90 degrees, for different heel angles. If you are beating at 30 degrees AWA while heeling at 20 degrees, your displayed apparent AWA is 1.5 degree in error without this correction, which is not done in many (most?) commercial systems, with some nasty consequences on further calculations of true wind, wind direction and vmg.

Thursday, February 3, 2011

The SeaTalk interface

The SeaTalk repeaters are used as backup displays, useful when the notebook and/or the outdoor monitor are not available for some reason. For example, in low battery situation when the more power hungry monitor has to be shut off. I first tried a custom 7-segment LED display for this function, but it proved unreadable in the sun. I then decided to go with Raymarine ST40 repeaters for their easy-to-read displays in all conditions.

I found all the information I needed on Thomas Knauf’s website ( The SeaTalk protocol is peculiar in that it requires 9-bit ‘bytes’ instead of the usual 8-bit, which is why it cannot be interfaced directly with a PC. The ATmega microprocessor has built-in support for 9-bit communication. The SeaTalk protocol requires that you set the 9th bit to 1 for the first byte of a command, and reset it to 0 for the remaining bytes of the same command.
I built the bidirectional interface described on Thomas Knauf’s website, even if I use it only one-way. For the transistors, I picked a 2N3904 (NPN) and a 2N3906 (PNP).

With this post, I begin to present some code examples for the Atmega128, using the WinAVR environment ( The following example shows how to send 5 SeaTalk commands that the repeaters can recognize, using interrupt-driven communication for efficiency. The SeaTalk bus is connected to the USART1 of the microprocessor. The commands are first built in a byte array before being sent to USART1, configured at 4800 baud per the SeaTalk protocol.

 /* Some inialization */
 volatile char stbuff[21];
 volatile uint8_t stindex = 0;
 uint16_t data;

 /* enable serial port UART1 */
 /* Set baud rate : 4800 @ 16 MHz */
 UBRR1L = (unsigned char)(207);
 /* Enable transmitter with 9 data bits  */
 UCSR1B = _BV(TXEN1) | _BV(UCSZ12);

 double stw = 5.9;  // speed through water (STW) in knots
 double depth = 50.0; // depth in feet
 double temp = 70.0;     // temperature in degrees F
 double awa = -32.0;  // apparent wind angle (AWA) in degrees
 double aws = 11.0;  // apparent wind speed (AWS) in knots

 // build the STW command
 data = (uint16_t)(stw * 10.0 + 0.5);
 stbuff[0] = 0x20;
 stbuff[1] = 0x01;
 stbuff[2] = data;
 stbuff[3] = data >> 8;
 // build the depth command
 data = (uint16_t)(depth * 10.0 + 0.5);
 stbuff[4] = 0x00;
 stbuff[5] = 0x02;
 stbuff[6] = 0x00;
 stbuff[7] = data;
 stbuff[8] = data >> 8;

 // build the temperature command
 data = (uint16_t)(temp * 10.0 + 0.5 + 100.0);
 stbuff[9] = 0x27;
 stbuff[10] = 0x01;
 stbuff[11] = data;
 stbuff[12] = data >> 8;
 // build the AWS command
 double dummy;
 uint8_t data8_1 = (uint8_t)aws;
 uint8_t data8_2 = (uint8_t)(modf(aws, &dummy) * 10.0 + 0.5);

 if(data8_2 == 10)
   data8_1 += 1;
   data8_2 = 0;
 stbuff[13] = 0x11;
 stbuff[14] = 0x01;
 stbuff[15] = data8_1;
 stbuff[16] = data8_2;

 // build the AWA command
 if(awa < 0.0)
  awa += 360.0;
 data = ((uint16_t)(awa + 0.5)) * 2;
 stbuff[17] = 0x10;
 stbuff[18] = 0x01;
 stbuff[19] = data >> 8;
 stbuff[20] = data;

 // enable the interrupt that fires when the USART1
 // is ready to accept a new character to send

// This interrupt routine will be called 21 times then will disable itself.

// Once a value is written in the UDR1 register, the USART will take care of
// sending it on the bus and the processor will be free to do its own things

// until the USART reports (by firing a new interrupt) that it is ready to accept
// another byte.
 // 4-5-4-4-4 : 21 bytes    1000-10000-1000-1000-1000   0-4-9-13-17
  case 0:
  case 4:
  case 9:
  case 13:
  case 17:
   UCSR1B |= _BV(TXB81); // set 9th bit to 1
   UCSR1B &= ~(_BV(TXB81));  // reset 9th bit to 0
 if(stindex < 20)
  UDR1 = stbuff[stindex++];
  UDR1 = stbuff[20];
  stindex = 0;
  UCSR1B &= ~(_BV(UDRIE1));  // disable interrupt
In the current installation, I use the ST40 Bidata repeater to show the boat speed through water (STW), but I cheat by sending the VMG value for depth, and the speed of the current for temperature. For the the ST40 wind repeater, I send the usual apparent wind angle, but I cheat again by sending the true wind speed value for AWS, as I like to see the AWA and TWS together on the same display.
The data sent to the repeaters are the running averages over the last 4 seconds, sent at the 10 Hz rate. However, the repeaters are internally refreshed only one time per second, and with a one second delay. The values newly displayed are thus the average of the first 4 seconds of the last period of 5 seconds (you have to read this twice).

Tuesday, February 1, 2011

Some pictures

In this first picture, we can see the 2 microprocessor Chameleon enclosures (, along the notebook, the waterproof monitor, the gyrocompass, the small GPS at the center and one of the SeaTalk repeaters.The small black housing at the bottom is home for the SeaTalk interface circuit. By design, there are no buttons or switches on the enclosures, only connectors. The field installable round connectors are Conxall Mini-Con-X available at Digi-Key.

The next one is a close-up of the first enclosure, with the MAVRIC-IIB controller, the USB converter at the right and the 8 V regulator at the bottom.

In the other enlosure, we can see the Olimex board, along 2 voltage regulators (5 V and 3.3V), and the small logic level converter between the two.