Arduino and NMEA

I do a fair bit of yacht racing, and something that becomes important for tactics in yacht racing is know how your boat performs in different conditions. You need to be able to answer questions like:

“With apparent wind-speed of 15 knots, coming from 120° to port, what is my best sail choice, and what speed should I be doing.”

The most important thing here is that you now have a target for the crew to sail for – you know that if you’re not within, say, 10% of your target speed something is wrong and you need to work on your trim, or you’ve got something dangling in the water, or stuck on your keel. Of course, as yachties we often think we have a gut-feel for these sorts of things, but a quantitative answer to the question above is very useful.

In the past I’ve sailed on yachts where the on-board instruments are connected to a laptop, and the it logs the data from the instruments, and presents all sorts of fancy graphs, and some of the more expensive software will certainly give you an answer to questions like the one I asked earlier. However, laptops and water (particularly salt water) don’t mix well at all, and they are not cheap to replace. What’s more, it will take the average weekend warrior an entire season, if not two, to get enough data to start producing useful answers to our questions, and having a laptop on board for all that time is just asking for it to get wet.

So, I’ve been thinking of alternate solutions to this problem and have decided to build a “little-black-box” for yachts. Somewhat like a flight data recorder for aircraft. The key difference being that it needs some sort of interface to capture changes in parameters, like which sails are up, and what the positions of various trimming devices are (such as jib cars).

The first experiment

Anyhow, I’ve made a very basic start on the system by using an Arduino prototyping board to read the NMEA 0183 data from my handheld GPS, and relay that data out through the serial port to my computer.

An Arduino wired up to a Garmin GPS 60

I plan on building a much more sophisticated bread-board prototype in the near future (have to buy a few more parts from Adafruit), and then I’ll look at stuffing it all into some water-tight packaging and taking it out sailing.

A printout of the NMEA 0183 data as logged by my basic prototype

The code

My Arduino “Sketch” (the program which runs on the board) uses Maarten Lamers’ NMEA library which needed a couple of modifications to work with the recent versions of the Arduino API:

In nmea.h, change the reference to WConstants.h to arduino.h:

//#include "WConstants.h"
#include "arduino.h"

In nmea.cpp, change the reference to WProgram.h to arduino.h:

//#include "WProgram.h"
#include "arduino.h"

The code for the actual sketch is very simple at this point, and is really just a matter of reading from one serial port, and writing into another, whilst funnelling the data through the NMEA library:

// -- This borrows very heavily from one of Maarten Lamers' 
// examples on how to use his NMEA library.
#include <SoftwareSerial.h>
#include <nmea.h>
SoftwareSerial nmeaSourceA(13, 12);
NMEA nmeaDecoder(ALL);
void setup()
{
    // Set up serial connection to computer. Eventually we'll write
    // to an SD card instead 
    Serial.begin(57600);
    Serial.println("NMEA Logger... v0.1");

    // Set up serial connection to NMEA source.
    nmeaSourceA.begin(4800);
}

void loop()
{
    // If there's anything to read from the serial port
    if (nmeaSourceA.available())
    {
       // We pass the data into the nmea decoder by calling
       // decode(). This function accumulates the bytes until
       // a valid NMEA sentence has been read. If a sentence has 
       // been read it returns true.
       if (nmeaDecoder.decode(nmeaSourceA.read()))
       {
          // We then write out the sentence
          Serial.print("Sentence = ");
          Serial.print(nmeaDecoder.sentence());

          // The data type term
          Serial.print(" Datatype = ");
          Serial.print(nmeaDecoder.term(0));

          // And the number of terms
          Serial.print(" COUNT(Terms) = ");
          Serial.println(nmeaDecoder.terms());
       }
   }
}

That’s all for today. I’ll keep you posted on how the device develops over time.

20 thoughts on “Arduino and NMEA

  1. G’day Guy
    I’m on a slightly similar path to you but for a different purpose. I want to capture the various nmea data streams from my instruments and send (multiplex) them to an android tablet where I can display them. Yep, you can buy all that stuff but A. it is expensive, and B. I like a challenge (or maybe just to mess around with stuff). On the boat that I crew on (Beneteau First 40) we have all the latest and greatest gear with the laptop (running Expedition) communicating with an iPad in the cockpit and yep, we have wet the laptop in a pretty rough ocean race. My boat is much more modest but I want to do similar things.
    I have played around for a while and can read my GPS and my Depth/speed … but not at the same time. The nmea streams of course come in simultaneously. I have a few arduinos so I will set up a master with slaves for each stream so the the data will be held by each slave until the master is ready to receive it. That’s the plan anyway.
    I also want to build a better wind instrument that compensates for mast movement and heel by using accelerometers and gyros. Lots of fun!
    cheers
    John

    1. Hi John,

      You can probably use a single Arduino to do the multiplexing. If you use a few instances of the SoftwareSerial library, you can check them in a round-robin fashion. Might simplify the setup.

      Cheers,

      Guy

      1. Hi there Guy … thanks for the reply and advice.
        Tho I’m not sure that the arduino is fast enough do do as you suggest.
        I know that if I do a little bit of extra processing on the nmea data coming in from one source, I start to occasionally lose the first few characters of the following sentences. But this could just be my bad programming.
        I’m also not sure about how good the software serial buffering is for multiple instances. But hey, I’ll give anything a shot.
        Cheers
        John

        … and keep the posts going on your project. Excellent stuff!

      2. Hi John,

        The ATMega328, which is the microprocessor on an Arduino runs at 20Mhz. NMEA0183, on the other hand, is typically transmitted at 4800 baud (4800 bits per second). The Arduino *should* be well capable of reading, buffering and multiplexing a handful of NMEA0183 signals – although I concede that it might take some crafty programming. I’m unable to do an experiment on this at the moment, but when I do I’ll keep you posted.

        Cheers,

        Guy.

      3. Guy, how did you get on with the Garmin GPS60 talking directly to the Arduino pins? In theory it’s belting out 9v on the rs232 port and the Arduino is expecting 5v at most.

        I’ve had some success with a Max232 chip to convert Rs232 to TTL, and I can see the NMEA sentences just fine.

        Good luck,
        Scott

      4. Hi Scott,

        I got on fine without any voltage conversion… I’d be surprised if it was doing 9 volts, as it only has two 1.5v batteries in it, if anything it is would be under-volting, but I don’t have a multimeter to check it with. I managed to read the data just fine – my challenge now is to write a multiplexing software UART, so that I can read data in from two sources.

        Cheers,

        Guy.

    2. Hello there,

      I am happy that you managed to read the Depth/Speed into arduino. Maybe you can give me some advice. I want to do the same with a Stowe Depth Transducer, which used to be connected to a Stowe Databox that recently passed away.

      There were 2 wires from the depth transducer to the databox. Besides I’ve read somewhere that Stowe/Robertson had some non-standard codes for Depth, but don’t know much about it.

      Guy, thanks for your post, I didn’t know nmea library works just fine in arduino! I tried your recipe with success, so far no memory issues.

    3. John,
      How did you get on with getting the instrument data?
      I’ve been wanting to do a similar thing with the Arduino so we can Bluetooth it to an Android tablet. That way we can see all the data we want in the cockpit rather than having to keep sticking our heads down below to look at the plotter and then the instruments. If we get the log and the speed over ground we can easily work out the tide.
      I like your idea of using the Arduino to get a more accurate wind speed too. It should be easy to work out with an MPU6050. I used one to build a segway a few years ago.
      From what you’ve described, it sounds like your instruments use the old nmea standard like on my boat. I’m thinking it should be possible to use one Arduino to collect the old nmea format and output it to the 0183 standard without too much difficulty, it really ought to be fast enough because I think the Baud rate is relatively slow for 0182.
      If you’re happy to share your code, I’d appreciate a look at it.

      Cheers,

      Julian.

  2. I tried to do this with my Garmin GPS 12 but did not have any luck. I see you are using Pins 12 and 13 for the serial connection (I assume data in and data out of the GPS device), however, I see that you also have other wires, I assume for ground and power. Do you need the power as the unit is self powered?

    1. Hi Thomas,

      I found that I did have problems if I didn’t hook up the +5 and GND lines. I don’t really understand why. In any case, I’ve written my own software serial port as well, which can read multiple streams of data, and queue them for writing to an SD card, without losing bits so far, but to get much more work out of the ATMega328, I’m going to have write a bit of a scheduler. I will have a blog post coming soon with more information.

      1. Thanks so much for the reply. I finally got it working. My problem is that I didn’t set the GPS unit up to interface with NEMA 183. I also set the baud rate up on the unit at 4800 baud and changed the code from 57600 to 4800. Not sure if I had to do that or not. I did find that it didn’t require me to connect the power or ground pins. I only connected Data In an Data Out to pins 12 and 13. The only thing I would like to change is the accuracy of the readout Right now it is essentially two decimal places and I would like three for accuracy. Do you have any idea where in the code this can be changed? Thanks again, this is fun stuff with lots of potential.

    2. Hello “guysherman” and Thomas!

      I’ve trying to do this with my Garmin GPS-12 today and I’m so close!

      So far I’ve been able to set up my GPS-12 to output NMEA 0183 V2.0 at 4800 baud, connect the Data Out to Pin 13, and Data In to Pin 12, and see that there is traffic coming across at about 2 Hz. However, the sentences are not being decoded and therefore the code never enters the second “if” statement where it has successfully found a sentence. I put a print statement right before the second “if” statement: Serial.println(nmeaSourceA.read());

      I’m definitely seeing traffic come across when I look at the terminal monitor (which I also have set to 57600 baud).

      Below is the tail end of the traffic I’m seeing. I clearly see a pattern in there. However, these characters are out of range of the normal ASCII values.

      My guess would be that something isn’t grounded/configured correctly within SoftwareSerial or there is something different about the NMEA library I just downloaded (03/05/2015). I did have to connect my Arduino GND to the GROUND (3 o’clock pin) on the GPS-12 in order for the data not to be all 255’s. Any chance this could be a serial configuration issue? Wrong parity or data bits? I’m not sure how to change any of those if that’s the case.

      I’m very interested in how Thomas Fanciullo got his to work! Sounds like he is doing the exact same thing as me. Would love to have the code if possible. If you guys can help, I would greatly appreciate it.

      Thanks!

      Phil
      philipjoep@hotmail.com

      ———
      Output:
      ———

      0
      91
      181
      133
      157
      187
      59
      157
      91
      139
      183
      0
      91
      181
      85
      157
      59
      59
      58
      91
      139
      183
      0

    1. I think the problem with adding a delay into a loop that uses the software serial is that it blocks the CPU, and so your software serial port isn’t able to do the bit-bashing it needs to do in order to send the data. I think you would be better off creating some sort of state machine, with time-based state changes to trigger events. The trick with using a software serial port is to keep the loop running as fast as you can because the run-time of your loop directly affects the maximum baud rate you can get out of your software serial port.

  3. Hi Guy
    I’ve tried your sketch and I got it working in my LOWRANCE fishfinder ( with RS232 shifter). I got the NMEA data through the serial monitor. I tested it with my laptop on the boat.
    I’m newbie in Arduino programming. I’ve bought SD card shield so that I must not bring my laptop on the boat. But I don’t get any success in programming yet.
    Can you share the code so that the NMEA data can store into the SD card ?

    thanks guy
    I’m sorry for my bad English

    Punto

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.