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<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:
Now, to see if they can talk.
References: