Connect Any NMEA-1083 Device to a Raspberry Pi

Just a quick update on my previous post about NMEA-0183 on the Arduino. Since I'm no longer using the Arduino, here's a quick down and dirty on how to interface with any NMEA-0183 device. The protocols in that post remain the same (RS-232, 422, 485, etc...), and the easiest way to connect them to a Raspberry Pi is through a USB to RS-422 adapter. This is the one I'm using, and I also have this one here for a later project. It's real self-explanatory: Plug in NMEA Out + into B, NMEA Out -  into A, and it goes (quick disclaimer: I haven't actually tried it with an NMEA device yet--I've been using my Arduino to simulate my depth sounder, and so those wires may actually have to be swapped with an actual device).

Once it's connected, you need to know the USB port's address in order to find that information. This step is really really easy. Make sure that you have it unplugged, and type this into the terminal:

ls /dev/tty*

and that will list a bunch of lines. You're main focus will be at the end of the list, with something like ttyUSB0 or something like that. Next, plug in your USB device (the NMEA-0183 device need not be powered on) and type in

ls /dev/tty* 

You should see an additional USB line at the end. Obviously, that's your NMEA's USB address. Make note of this.

Before we go on, a quick word on these addresses: if you have more than one USB device plugged in, and you unplug one of them assigned to USB0 or USB1, then the other USB's address will shift down by 1--such that your script won't work. So basically, keep everything plugged in that you'll be using. If you unplug something, you'll have to rework the script to reflect the new address.

The script for my DST-800 plugged into my Raspberry Pi is below, but it can pretty much work for everything. Here's the basic architecture:

It reads a single line coming in from the USB port, extracts the actual sentence by splitting it by the * symbol and removing the $ sign. It then calculates it's checksum, and compares that to the given checksum. If it's valid (meaning it's a valid NMEA sentence), it splits the sentence into its comma separated values, and runs specific code depending on the title.

For example, I convert the temperature from Celsius to Fahrenheit, and add a .5 depth sounder offset to that sentence.

Whenever it receives a sentence, it runs its specific code, then it sends it to a UDP port to another script for further processing and compilation. Now, one of the reasons why I wanted to switch from the Arduino to the Raspberry Pi was for fault protection. I'm checking for a valid NMEA sentence, but what if the sensor wigs out and stops sending data?

If it goes for more than 10 seconds without receiving a depth sentence, it assumes the DST-800 has failed (or circuit breaker popped, or whatever). In this case, it creates a new NMEA sentence to let me know. Example:


which then goes through the gonkulator script (more on that to follow), through kplex, and into OpenCPN or whatever device I'm using since this is a valid NMEA sentence, and it tells me that the DST hasn't sent a sentence in 4.5 minutes. That will continue to tick up forever. If I see that, then I know I need to go reset the circuit breaker or something like that.

More to follow on what happens next.

The script:

 import sys  
 import serial  
 import math  
 import operator  
 import time  
 import socket  
 DST_IP = ""  
 DST_PORT = 5005  
 vlwfirst = 1  
 vlwinit = 0.0  
 t_dpt = 0  
 t_print = time.time()  
 t_fail = 0.0  
 sddpt = ''  
 mtw = ''  
 yxmtw = ''  
 vwvhw = ''  
 vlw = ''  
 vwvlw = ''  
 ser = serial.Serial('/dev/ttyUSB0', 4800, timeout=1)  
 while True:  
   hack = time.time()  
   dst_raw = ser.readline()  
   if "*" in dst_raw:  
     dst_split = dst_raw.split('*')  
     dst_sentence = dst_split[0].strip('$')  
     cs0 = dst_split[1][:-2]  
     cs = format(reduce(operator.xor,map(ord,dst_sentence),0),'X')  
     if len(cs) == 1:  
       cs = "0" + cs  
     if cs0 == cs:  
       sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  
       dst_vars = dst_sentence.split(',')  
       title = dst_vars[0]  
       if title == "SDDPT":  
         sddpt = dst_raw[:-2]  
         sock.sendto(sddpt, (DST_IP, DST_PORT))  
         t_dpt = hack  
         t_fail = 0.0  
       if title == "YXMTW":  
         mtw = dst_vars[0] + "," + str(float(dst_vars[1]) * 9 / 5 + 32) + ",F"  
         cs = format(reduce(operator.xor,map(ord,mtw),0),'X')  
         if len(cs) == 1:  
           cs = "0" + cs  
         yxmtw = "$" + mtw + "*" + cs  
         sock.sendto(yxmtw, (DST_IP, DST_PORT))  
       if title == "VWVHW":  
         vwvhw = dst_raw[:-2]  
         sock.sendto(vwvhw, (DST_IP, DST_PORT))  
       if title == "VWVLW":  
         if vlwfirst == 1:  
           vlwinit = dst_vars[1]  
           vlwfirst = 0  
         trip = float(dst_vars[1]) - float(vlwinit)  
         vlw = "VWVLW," + dst_vars[1] + ",N," + str(trip) + ",N"  
         cs = format(reduce(operator.xor,map(ord,mtw),0),'X')  
         if len(cs) == 1:  
           cs = "0" + cs  
         vwvlw = "$" + vlw + "*" + cs  
         sock.sendto(vwvlw, (DST_IP, DST_PORT))  
   if (hack - t_dpt) > 10.0:  
     if (hack - t_print > 1.0):  
       t_fail += 1.0  
       dst_sentence = "IIXDR,DST_FAIL," + str(round(t_fail / 60, 1))  
       cs = format(reduce(operator.xor,map(ord,dst_sentence),0),'X')  
       if len(cs) == 1:  
         cs = "0" + cs  
       dst_sentence = "$" + dst_sentence + "*" + cs  
       sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  
       sock.sendto(dst_sentence, (DST_IP, DST_PORT))  
       t_print = hack  


  1. Hello, thanks for the post it's really interesting!
    Hope it's not to late for asking...

    I'm connecting a DST800 Transductor to a Raspberry Pi and to connect between them I bought the same RS-422 Adapter:

    The problem is when I try to read the NMEA sentences with a basic C# code:
    static void Main(string[] args)
    SerialPort sp = new SerialPort("/dev/ttyUSB0", 4800);
    sp.ReadTimeout = 1000;

    while(true) {
    int i = sp.ReadChar();
    char c = (char) i;


    The data recived it's incorrect, doesn't have any sence and I don't know for what reason could be.
    Here I upload a picture with the recived data in Ubuntu:

    What do you think can be happen? It is a wrong USB adapter? Or needs a post software conversion after reciving data?

    Thanks you,

    1. Can you confirm that you have the NMEA-0183 DST800, and not the NMEA-2000?

    2. Hi Connor,

      thanks for sharing! That's exactly what I've been searching for.
      I'm a newbie to the Raspberry Pi, so I just wanted to check if I understand everything: Is it right that I only need to connect the transducer cable with the
      RS-422 to USB adapter and the adapter via USB to the Pi? Is the voltage not to high for the Pi?
      I hope you read this :)
      Thank you,

    3. I've been experiencing the same issues. I purchased a RS485 Serial to USB with a CH341 Chipset (basically the same adaptor used in this post) I also get a garbled mess of characters in my output stream and no sensible data containing any NMEA identiers (like the $ symbol). I spent a whole day locating and installing a special driver for the CH341 Chip and my Raspberry Pi B identifies the device and chip, however the problem persists. I have a low power warning on PI startup so I ordered a new power cable with 5 volts, 3 amps instead of 5 volts, 1.2 amps (standard cell phone charger type) to see if the extra amps fixes the issue. There are a lot of PI forum posts about Serial to USB issues caused by grounding loops. I'm not sure if that applies to the 2 wire version like this? Any help from someone who's fixed this issue would be appreciated. Do we need higher quality adapters?

    4. Katharina--yes, you connect the transducer directly to the RS-422 USB adapter, and then plug that adapter into the USB port on the Raspberry Pi. The voltage can potentially go up to 12v, but the RS-422 USB adapter can handle it. Just do NOT plug the transducer cables directly into any GPIO or Serial pins on the raspberry pi, that's when you get trouble and will fry your pi.

    5. Daniel, I had to go through multiple converters because I'm pretty sure they're just shitty and low quality. I can't remember when I settled on, but there really isn't any rhyme or reason to it. I just ordered a bunch and eventually found one that worked. I think the soldered connections inside the wire housing (where you plug the + and - wire into) are apt to come loose. It is imperative that you do not skimp on quality and get the most expensive cables/adapters here. It sounds like you did for the power supply, which is good, but also make sure you don't get the cheapest adapter you can find... you get what you pay for here.


Post a Comment

Popular Posts