Skip to main content

An inexpensive dual-channel AIS receiver


Raspberry Pi 3

The Automatic Identification System (AIS) is an automated transponder system for marine vessels, developed as a collision avoidance tool. This page shows how to set up a dual-channel AIS receiver using a Raspberry Pi 3 (Model B) [1] and any generic RTL-SDR USB stick. [2] We will forward the raw NMEA AIS feed via UDP to from a static IP, using a DigitalOcean account.


The overall scheme will be as follows:

[UHF AIS signal to NMEA feed (Pi)] -> [UDP to TCP (Pi)] -> [SSH tunnel TCP (Pi) to TCP (DigitalOcean)] -> [TCP (DigitalOcean) to UDP (].

The SSH tunnel is kept alive by autossh, which runs as daemon in the background. You are free to choose different ports instead of the defaults 10110 and 1234 chosen here, just make sure to change the files below accordingly. We choose the Linux command line tool rtl_ais as decoder. UDP/TCP port forwarding is done by socat. Both of these programs also run as daemon processes and are automatically restarted if needed.

Prepare your Pi

Install a standard Raspbian system image on your SD card. Update the OS and install git, libusb, librtlsdr, rtl-sdr, socat, autossh using:

sudo apt-get update && sudo apt-get upgrade
sudo apt-get install git nmap socat iptraf autossh
sudo apt-get install rtl-sdr librtlsdr-dev libusb-1.0-0-dev

Install SSH keys

First, set up SSH keys for your Pi to access it via WLAN/LAN from a computer in your local network without entering a password. A tutorial can be found at DigitalOcean. After you are done with this step, you are able to configure your Pi via remote console. Remove the ability to log on via password for added security. In most of the cases, you will not have a static IP address with your residential internet. Once you register the cheapest account (currently $5/month - link with my referral code), you will have a static IP for AIS sharing purposes. Lock down your digitalocean account with two-factor authorization. Set up SSH keys and disable password access for this account, too. You can use different keys for your work computer, and the Pi accessing the account.

Caveat: when you install the keys for DigitalOcean on your Pi, connect to DigitalOcean once as user pi on your Pi, and also once as root. SSH will otherwise fail to auto-connect on boot, because it will ask to add the host IP to the known_hosts file.

Set up the RTL-SDR USB stick

Plug the USB stick into the Pi. The output of lsusb should be similar to this:

pi@raspberrypi:~ $ lsusb
Bus 001 Device 004: ID 0bda:2832 Realtek Semiconductor Corp. RTL2832U DVB-T
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

Use git to download rtl-ais, follow the instructions on the github page, and copy the compiled rtl_ais executable to /usr/local/bin/.

There will be a small frequency offset for the USB stick, if it is a generic non-compensated one. This offset depends on temperature and your specific hardware. To determine the offset, let the USB stick warm up for 20 minutes first. The easiest way to proceed is to run SDR#, or any other SDR software which allows to display a waterfall plot, on your desktop. A typical AIS signal should look like this, using the correct parameters. The AIS frequencies A and B are at 161.975 MHz and 162.025 MHz. Other ways of determining the frequency offset (via tools that use GSM850 or GSM900 frequencies) turned out to be nonlinear/unreliable for my USB stick. These parameters work for my specific USB stick:

rtl_ais -l 161.966M -r 162.015M -g 48 -h

Tip: Just enter the two frequencies you see the signal at as parameters to rtl_ais like above, instead of giving a ppm offset. Don't forget to increase the gain if needed. You can check the output of rtl_ais to the default UDP port 10110 on localhost with ncat:

ncat -l -u 10110

The output should be strings similar to !AIVDM,1,1,,A,403OwoQv2bBSDreTq0GEg6w02H;p,0*43, which is an encoded AIS message from channel A. If you are near a port and your antenna is good, you should see a few messages per minute or more. You can use ncat or socat to forward the UDP traffic to a local computer running e.g. OPENCPN to plot the ships your receiver sees on a map, and check your antenna range.

System configuration (Raspberry Pi)

Now we want to make the running system set-and-forget. We also will tunnel the UDP packets via forwarded TCP port via a persistent SSH connection to our server at DigitalOcean.

In /etc/systemd/system/, create a file ais.service with the following content (adjust your frequencies and gain values):


ExecStart=/usr/local/bin/rtl_ais -l 161.966M -r 162.015M -g 48 -h


A file autossh.service containing (adjust user@ according to your username and IP):

Description=AutoSSH TCP tunnel from pi to digitalocean

ExecStart=/usr/bin/autossh -M 0 -N -q -o "ServerAliveInterval=30" -o "ServerAliveCountMax=3" -L 1234: user@ -i /home/pi/.ssh/id$


And a file called udp-tcp.service:

Description= forward UDP port 10110 to TCP port 1234

ExecStart=/usr/bin/socat -v UDP-LISTEN:10110,fork TCP:localhost:1234


Then start and enable-on-boot each one of the three services above, replacing **** the first part of the filename:

systemctl start ****.service
systemctl enable ****.service

Check your setup on the Pi

sudo systemctl status udp-tcp.service -l should output something similar to:

● udp-tcp.service - forward UDP port 10110 to TCP port 1234
   Loaded: loaded (/etc/systemd/system/udp-tcp.service; enabled)
   Active: active (running) since Thu 2016-10-13 17:17:04 EDT; 6 days ago
 Main PID: 570 (socat)
   CGroup: /system.slice/udp-tcp.service
           ├─  570 /usr/bin/socat -v UDP-LISTEN:10110,fork TCP:localhost:1234
           └─31282 /usr/bin/socat -v UDP-LISTEN:10110,fork TCP:localhost:1234

Oct 20 14:35:20 raspberrypi socat[570]: > 2016/10/20 14:35:20.381938  length=49 from=5615126 to=5615174
Oct 20 14:35:20 raspberrypi socat[570]: !AIVDM,1,1,,A,403OwoQv2bBSDreTq0GEg6w02H;p,0*43\r
Oct 20 14:35:20 raspberrypi socat[570]: > 2016/10/20 14:35:20.385932  length=49 from=5615175 to=5615223
Oct 20 14:35:20 raspberrypi socat[570]: !AIVDM,1,1,,B,403OwoQv2bBSDreTq0GEg6w02H;r,0*42\r
Oct 20 14:35:21 raspberrypi socat[570]: > 2016/10/20 14:35:21.720172  length=49 from=5615224 to=5615272
Oct 20 14:35:21 raspberrypi socat[570]: !AIVDM,1,1,,A,15NTHB001=reJ2nGFi`1J1<`0t1m,0*39\r
Oct 20 14:35:26 raspberrypi socat[570]: > 2016/10/20 14:35:26.318703  length=49 from=5615273 to=5615321
Oct 20 14:35:26 raspberrypi socat[570]: !AIVDM,1,1,,B,15MwQn0P0iJeF@lGFErp3gvl0@?H,0*57\r
Oct 20 14:35:32 raspberrypi socat[570]: > 2016/10/20 14:35:32.588169  length=49 from=5615322 to=5615370
Oct 20 14:35:32 raspberrypi socat[570]: !AIVDM,1,1,,B,15NTHB0017reJ8@GFjE1J1>v0PRT,0*58\r

The command iptraf lets you to see outgoing UDP packets. You can use ncat to quickly troubleshoot your port forwarding by sending simple text messages through the SSH tunnel. The load average on my Pi is 0.25 - there is plently of processing power left for other tasks.

System configuration (DigitalOcean)

Log into your DigitalOcean account and install socat and iptraf.

sudo apt-get update && sudo apt-get upgrade
sudo apt-get install socat iptraf

We again run socat as a daemon, it forwards the UDP packets to the AIS sharing service (change the site/port according to your needs). Put a file named tcp-udp.service in /etc/systemd/system/, changing ???? to your assigned port for

Description= forward TCP port 1234 to UDP port

ExecStart=/usr/bin/socat -v TCP-LISTEN:1234,fork


Then start, and enable-on-boot the service:

systemctl start udp-tcp.service
systemctl enable udp-tcp.service

You can check the forwarding service using systemctl status tcp-udp.service -l as before. Outgoing UDP packets will show up in iptraf.

That's all - your AIS receiver/forwarder system is up and running.

[1] A good starter kit, including everything you need besides the USB dongle, is this one.
[2] I recommend the slightly more expensive version by instead of a generic cheap dongle. It has <2 ppm frequency offset which should require no frequency adjustment, a metal case, and an SMA connector for the antenna - absolutely worth the extra $10.


Comments powered by Disqus