OpenCPN on the Raspberry Pi 2 with AIS

This past weekend I gave a presentation to a group of local sailors and boaters touting the benefits of running OpenCPN on a System-on-a-chip board such as the Raspberry Pi.

In preparation for the talk, I rebuilt OpenCPN on the newest generation Raspberry Pi 2, running the most current source code available on git at the time (4.1.412). I didn’t have the time to do any performance tuning of the system, and ran it out of the box all weekend long. OpenGL was not running appropriately, so performance was less than previous installations, but it did run out of the box, following the Raspberry Pi installation steps, with the additional step of compiling OpenCPN from source to get the most recent version.

However, I did add a new feature to the installation, and one that I am extraordinarily happy with — the ability to receive AIS data on OpenCPN running on a Raspberry Pi 2!

First AIS Contact

The first AIS contact!

In order to read AIS messages, I purchased a demo board of a product called dAISy designed by Adrian Studer. I’ve had the board in my hands for a few months, but as always work and life gets in the way of projects such as this. This past weekend I sailed my boat the 35nm or so from Tacoma to Poulsbo and had a few hours to play around with the chartplotter AND dAISy in an environment where the messages could be received. In short, it worked exceptionally well, and you can see the very first AIS contact that was picked up by the system just as we exited the north end of Colvos Passage in the photo above.

dAISy is a very well designed board that is easy to use. Just connect an antennae to the BNC connector, and a USB cable to the mini-USB port. In the current Raspbian image, all the required kernel support is set up, so simply plugging in the board is enough.

To test that it is working, perform the following test:

sudo apt-get install screen
screen /dev/ttyACM0

To exit screen, type CTRL-A, followed by K. At this point you should have a terminal window set up, and if you are within range of AIS targets you should see a list of AIVDM NMEA messages, that look something like this:

!AIVDM,1,1,,A,85Mwp`1Kf3aCnsNvBWLi=wQuNhA5t43N`5nCuI=p<IBfVqnMgPGs,0*47 !AIVDM,2,1,6,A,8>qc9wiKf>d=Cq5r0mdew:?DLq>1LmhHrsqmBCKnJ50,0*30
!AIVDM,2,1,1,A,55?MbV02;H;s<HtKR20EHE:0@T4@Dn2222222216L961O5Gf0NSQEp6ClRp8,0*1C

If you are not within range of AIS targets, you can still confirm that dAISy is responding by accessing it’s menu. Simply press [esc] and the menu will display such as the screencapture from Windows shows below:

AIS

If you turn on debug messages, and you are out of range (or have a very low signal) then you will see a series of messages like the following:
sync A RSSI=-085dBm
error: invalid stuff bit
sync A RSSI=-073dBm
error: CRC error
sync A RSSI=-086dBm
error: invalid stuff bit
sync B RSSI=-071dBm
error: CRC error
sync B RSSI=-087dBm
error: CRC error
sync B RSSI=-086dBm
error: invalid stuff bit

Then the last step is to render the targets in OpenCPN. It’s a fairly simple process of creating a new data connection. Go to Options -> Connections | Data Connections, and Add Connection. Select a Serial message, and set the DataPort to the dAISy USB message port (generally /dev/ttyACM0). Set the Baudrate to 9600, and uncheck Control checksum. Apply and return to OpenCPN.

If you think you have done everything correctly, but you are still not seeing AIS contacts or messages, and especially if ‘screen’ is showing messages, make sure that your user is added to the ‘dialout’ group. To add yourself to the group:
sudo usermod -a -G dialout $USER

Otherwise, enjoy the benefits of knowing where other vessels are, where they are heading, and who they are!

20150426_112418

20150426_112546

I make Fire! Again!

As mentioned in I make Fire (the first time), the propane system we inherited when we purchased our boat was old, corroded, and out of compliance with the most recent regulations.

The existing Magic Chef range and oven, while it worked in that it produced a good flame, did not have a propane thermocouple. This little safety device is designed to shut down the flow of propane in the event that the flame is extinguished for some reason. So for the past year, whenever we used it, we had to be careful that the flame didn’t blow out and fill the cabin with explosive propane gas. In short, it needed to be replaced.

20140525_142236 20140525_142218

Unfortunately, marine stoves and ranges cost over $1000, even online, so we decided to go with an RV model at less than a third the cost. It has 3 cooktop burners, an oven/broiler, and yes, a thermocouple. It also has a piezo-ignition so that we don’t need to light from a match or lighter, just click the button.

This weekend we installed it.  After removing the old stove, we cleaned the recessed area, cut away and pulled out the old corroded copper lines, and ran a brand new LPG rubber hose from the tank outside to the appliance.

20140525_143124 20140525_171053

The next step was to install the new range. Of course no boat project can go completely smoothly, and in this case the range that was shipped to us was the larger model than the one we had ordered. It didn’t fit into the cutout by 1/4″. So I had to use a router and cut away a bit of the wall. After that, the range slid into place perfectly.

20140601_182206

The last step was to connect the propane hose to the T in the cockpit, turn on the valve and solenoid, drain the air from the line (just a few seconds), and test:

20140601_182032 20140601_182053

Fire hot. Fire good.

 

 

 

 

 

Autostart OpenCPN on Boot

Since this project’s main intent is to create a dedicated chartplotter/autopilot, it doesn’t make sense that I need to open a terminal window, start the gpsd service, and then double-click the OpenCPN icon on the desktop to get everything up and running. It should all just start up once the RPi boots up, and since it’s simply a Linux computer, this is possible, and really quite easy

First, the gpsd service needs to be started. As mentioned previously, there are a few terminal commands that are used to start the service. I simply created a pearl script in /etc/init.d/  that performs those steps:

#! /bin/sh
# /etc/init.d/startgps
#
### BEGIN INIT INFO
# Provides: 			noip
# Required-Start:		$remote_fs $syslog
# Required-Stop:		$remote_fs $syslog
# Default-Start:		2 3 4 5
# Default-Stop:			0 1 6
# Short-Description:	Simple script to start a program at boot
# Description:			A simple star/stop script
### END INIT INFO

echo 'Starting GPSD'
sudo service gpsd restart
sudo killall gpsd
sudo gpsd /dev/ttyAMA0 -F /var/run/gpsd.sock

exit 0

Then, I registered it to run at startup using the update-rc.d command. After a reboot, I was able to simply open a terminal window and execute xgps successfully, proving that the GPS stream was available.

The next step was to launch OpenCPN. I tried many different ways, but many had difficulties reading the user config settings. The simplest way, that worked great, was to create a launcher and place it in an autostart folder inside /home/pi/.config. The launcher file was already on the desktop, so it was a simple copy/paste process.

And with that, on reboot, OpenCPN launches, and after a minute or two GPS acquires the satellites and the chartplotter portion of the project is complete.

Resources:

They Can Talk?

The next big hurdle in this DIY chartplotter project (which I need to name, because that’s too long to type), is to get the Raspberry Pi microprocessor to communicate with the Arduino motor control unit in the stern.

After talking to a few people, including Al Thomason (who has much more experience in Arduino and microprocessors than I), I have decided that the communication architecture will be NMEA 0183 over the I2C bus. I chose NMEA 0183 is a very easy, standardized messaging protocol, with many devices supporting it. It makes sense that this project, in the end, should be able to communicate with other devices. The new NMEA 2000 format has all sorts of political and copyright issues that I don’t want to deal with until it gets figured out by others. I chose I2C because it’s only 3 wires, and you can have over 100 devices on the bus (ignoring details like capacitance, interference, and device support). With a repeater, or something similar, the distances between devices shouldn’t be a problem either.

So, with that in mind, I decided to perform a test to see if I could get the Arduino device and the Raspberry Pi device to communicate with each other. For this test, the communication is going to be “backwards” – that is, the Arduino is going to send a message to the Raspberry Pi, rather than the other way around.

Borrowing heavily from pages on the web , I wrote a simple Arduino sketch that counts from 0 to 360 and back to 0 again, every second, infinitely, to generate a fake compass heading. I then generate an NMEA $HCHDG sentence with that heading inserted – once consumed by OpenCPN, the heading should slowly rotate around the compass rose back and forth. The code for the sketch is here:


#include <Wire.h>

#define SLAVE_ADDRESS 0x04
int heading = 0;
bool increasing;
String buffer;

/*
    Setup Method
*/
void setup()
{
    //Setup Arduino for I2C Slave
    pinMode(13, OUTPUT);
    Serial.begin(9600);
    Wire.begin(SLAVE_ADDRESS);
    Wire.onReceive(receiveData);
    Wire.onRequest(sendData);

    Serial.println("I2C Configured");

    //Setup communications
    buffer = "";
    increasing = true;
    heading = 0;

}

/*
    Loop Method
*/
void loop()
{
    //Get compass heading
    getHeading();

    //Send Compass heading message across wire
    sendData();

    delay(200);
}

/*
    Method to receive data across I2C Bus
*/
void receiveData(int byteCount)
{
    while (Wire.available())
    {
        char c = (char) Wire.read();
        buffer += c;
        if (buffer.endsWith("\r\n"))
        {
            Serial.println(buffer);
            buffer = "";
        }
    }
}

/*
    Method to send data across I2C bus
*/
void sendData()
{
    Wire.beginTransmission(SLAVE_ADDRESS);
    Wire.write(getNMEA());
    Wire.endTransmission();
}

/*
    Method to return current heading as an NMEA0183 HCHDG message
*/
char *getNMEA()
{
    char nmeastr[32] = "$HCHDG";
    char intStr[8];

    strcat(nmeastr, itoa(heading, intStr, 10));
    strcat(nmeastr, ",,,,");

    //Generate checksum
    int checksum = 0;
    for(int i=0; i&lt;strlen(nmeastr); i++)
    {
        checksum ^= nmeastr[i];
    }

    strcat(nmeastr, itoa(checksum, intStr, 10));
    strcat(nmeastr, "\r\n");

    Serial.println(nmeastr);
    return nmeastr;
}

/*
    Method to get the current compass heading
*/
void getHeading()
{
    //TODO: Pull from digital magnetometer device. Currently just makes up a heading
    if (increasing)
    {
        if (heading < 360)
        {
            heading++;
        }
        else
        {
            increasing = false;
        }
    }
    else
    {
        if (heading > 0)
        {
            heading--;
        }
        else
        {
            increasing = true;
        }

    }
    Serial.print("Current Heading : ");
    Serial.println(heading);
}

As for the physical connection between the devices, I decided to go with standard CAT-5 cable. I had a couple extra breakout boards for Ethernet jacks, so I wired those up directly to the SDA and SCL lines on both devices, using only three of the 8 wires available:

IMG_20130829_104530

Now, to see if they can talk.

References:

A DIY Chartplotter

It only took two evenings to get a Raspberry Pi chart plotter built out.

Yesterday I got OpenCPN up and running following instructions found on the web, and today I finished the process to the point that the hardware is a fully functional chart plotter.

The first improvement that had to be made was getting charts installed in OpenCPN. Thankfully NOAA provides free versions of nautical charts for US Waters and most frequented coasts regionally. It was simply a matter a downloading the appropriate charts (Washington State, and Region 15, Puget Sound) and unzipping them to a folder. I then added that folder to OpenCPN using the built-in options screen, and after a few minutes of compiling, the charts displayed.

IMG_20130821_174054

Then I needed to add GPS capability. First, I hacked together a few wires to an existing Venus GPS Module that I had from a previous Arduino project. This was a simple matter of soldering 3.3v power, ground, and TX/RX digital inputs between the items:

IMG_20130822_181042

Then I installed the GPSD service from the web, run the service, create a socket for it, and verify that the hardware is receiving the signal. Currently I need to hand-type this sequence each time I reboot the microcomputer: 
$ sudo service gpsd restart
$ sudo killall gpsd
$ sudo gpsd /dev/ttyAMA0 -F /var/run/gpsd.sock

Eventually this will be added to a script that will run on boot.

And then to test: 
$ sudo cgps
or
$ sudo xgps

And behold, signals from outer space:

IMG_20130821_191632

Now that all the pieces are in place, the final step is to add this GPS device to OpenCPN so that it can read the information:

IMG_20130822_180807

In this picture you should be able to see a rendered nautical chart of Puget sound, Heading, GPS satellite status, GPS location, and  Compass gauges on the left, and my “boat”, sitting off in Issaquah, since that’s where my GPS device is located.

It’s running at about 80% of the Raspberry Pi’s capability, at 1280×1024 with no overclocking.

And boom goes the dynamite.

It’s ALIVE!

My Raspberry Pi board showed up in the mail today. After a few minutes downloading and expanding the operating system, I got the machine up and running:

IMG_20130821_132454

Thanks to the very helpful walkthrough/tutorial at http://www.agurney.com/raspberry-pi/pi-chart , I now have version 3.2.0 of OpenCPN running on a brand new Raspberry Pi Model B. At this point I just have it up and running… No charts have been installed, GPS is not hooked up, there are no plugins installed, etc. But OpenCPN is clearly running:

IMG_20130821_143807

Meanwhile, on the Arduino side of the system, I was playing around with a 128×64 Graphic LCD screen that I had laying around. I plugged it in and found a library written for it that worked with very few changes. I doubt that the Arduino will actually drive an LCD, as it’s not in a convenient location to do so (down near the rudder post), but it was good to see that it worked regardless.

IMG_20130821_145943

An Easy Tile Upgrade

While wandering through a home-improvement store, my wife came across some peel-and-stick tiles. We looked at a few different options, but decided to go with the product that seemed to be the easiest to install – a “stainless” pattern with no need for any grout at all. We simply cut the tiles to size, using a razor blade to cut between the tiles, peeled of the adhesive backing:

IMG_20130818_161855

… and pressed down:

IMG_20130818_161822

There’s not a straight line on a boat, and the “rectangle” countertop was no exception. So of course some tiles needed to be cut — a Dremel made quick work of these tiles, and it was surprisingly easy to get straight cuts with it.

After a few hours, the project was complete. Here are some before-and-after shots:

IMG_20130818_150524IMG_20130818_171733

IMG_20130818_150015IMG_20130818_171744