NMEA2000 GPS-Position in den Arduino einlesen und formatiert ausgeben

Die GPS Position, Kurs und Geschwindigkeit werden vom HDS gesendet, aus dem NMEA2000 Netzwerk in den Arduino Mega eingelesen und per USB dann formatiert in der Konsole ausgegeben.

Es kommt ein schneller Kurs/Speed Datensatz 4x pro Sekunde aus dem NMEA2000 Netz
PGN 129026 COG & SOG, Rapid Update
und ein GPS Datensatz 1x pro Sekunde
PGN 129029 GNSS Position Data

Diese beiden Datensätze werden eingelesen, zerlegt und die interessanten Werte werden auf der Konsole ausgegeben.

Hier das Programm:

/ Die Positionsdaten, SOG und COG werden aus dem 
// NMEA2000 Netz in den Arduino eingelesen und dann 
// formatiert ausgegeben.
//
// Matthias Busse 2.12.2016 Version 1.0

#define N2k_CAN_INT_PIN 21 
#define MCP_CAN_RX_BUFFER_SIZE

#include <SPI.h>
#include <Arduino.h>
#include <NMEA2000_CAN.h>
#include <N2kMessages.h>
#include <N2kMessagesEnumToStr.h>

typedef struct {
  unsigned long PGN;
  void (*Handler)(const tN2kMsg &N2kMsg); 
} tNMEA2000Handler;

void COGSOG(const tN2kMsg &N2kMsg);
void GNSS(const tN2kMsg &N2kMsg);

tNMEA2000Handler NMEA2000Handlers[]={
  {129026L,&COGSOG},
  {129029L,&GNSS},
  {0,0}
};

template<typename T> void PrintLabelValWithConversionCheckUnDef(const char* label, T val, double (*ConvFunc)(double val)=0, bool AddLf=false ) {
  Serial.print(label);
  if (!N2kIsNA(val)) {
    if (ConvFunc) { Serial.print(ConvFunc(val)); } else { Serial.print(val); }
  } 
  else Serial.print("not available");
  if (AddLf) Serial.println();
}

void setup() {
  Serial.begin(115200);
  NMEA2000.EnableForward(false);
  NMEA2000.SetMsgHandler(HandleNMEA2000Msg);
  NMEA2000.Open();
}

void loop() {
  NMEA2000.ParseMessages();
}

void COGSOG(const tN2kMsg &N2kMsg) {
// PGN 129026 COG & SOG, Rapid Update.
// kommt typisch 4x pro Sekunde
    unsigned char SID;
    tN2kHeadingReference HeadingReference;
    double COG, COG2;
    double SOG;
    
    if (ParseN2kCOGSOGRapid(N2kMsg,SID,HeadingReference,COG,SOG) ) {
      Serial.print("COG: ");
      COG2=COG*57296/1000; // NMEA2000 ist radians > in Grad umrechnen
      if(COG2<0.0) COG2=360+COG2; // 0..180 und 0..-179 in 0..360 Grad umrechnen
      Serial.print(COG2,0); // in Grad
      Serial.print(" Grad, ");
      Serial.print("SOG: ");
      Serial.print(SOG*1.9438,2); // in kn (NMEA2000 ist m/s) (m/s * 1.9438 = kn)
      Serial.println(" kn ");
    } 
    else {
      Serial.print("Fehler PGN: ");
      Serial.println(N2kMsg.PGN);
    }
}

void GNSS(const tN2kMsg &N2kMsg) {
// PGN 129029 GNSS Position Data
// kommt typisch 1x pro Sekunde
    unsigned char SID;
    uint16_t DaysSince1970;
    double SecondsSinceMidnight; 
    double Latitude;
    double Longitude;
    double Altitude; 
    tN2kGNSStype GNSStype;
    tN2kGNSSmethod GNSSmethod;
    unsigned char nSatellites;
    double HDOP;
    double PDOP;
    double GeoidalSeparation;
    unsigned char nReferenceStations;
    tN2kGNSStype ReferenceStationType;
    uint16_t ReferenceSationID;
    double AgeOfCorrection;

    if (ParseN2kGNSS(N2kMsg,SID,DaysSince1970,SecondsSinceMidnight,
                  Latitude,Longitude,Altitude,GNSStype,GNSSmethod,
                  nSatellites,HDOP,PDOP,GeoidalSeparation,
                  nReferenceStations,ReferenceStationType,ReferenceSationID,
                  AgeOfCorrection) ) {
      Serial.print("Breite: ");
      Serial.print(Latitude,5); // 5 Kommastellen, in Grad ("-"=Süd, “+”=Nord) 
      Serial.print(" Grad, ");
      Serial.print("Laenge: ");
      Serial.print(Longitude,5); // 5 Kommastellen, in Grad ("-"=West, “+”=Ost)
      Serial.print(" Grad, ");
      Serial.print("Hoehe: ");
      Serial.print(Altitude,1);
      Serial.print("m, "); 
      Serial.print("Sats: ");
      Serial.print(nSatellites);
      Serial.println(" ");              
    } 
    else {
      Serial.print("Fehler PGN: ");
      Serial.println(N2kMsg.PGN);
    }
}

void HandleNMEA2000Msg(const tN2kMsg &N2kMsg) {
  int iHandler;
  
  for (iHandler=0; NMEA2000Handlers[iHandler].PGN!=0 && !(N2kMsg.PGN==NMEA2000Handlers[iHandler].PGN); iHandler++);
  if (NMEA2000Handlers[iHandler].PGN!=0) {
    NMEA2000Handlers[iHandler].Handler(N2kMsg); 
  }
}

Die Konsolenausgabe sieht dann so aus:

Breite: 54.26037 Grad, Laenge: 10.08289 Grad, Hoehe: 42.4m, Sats: 7
COG: 247 Grad, SOG: 0.14 kn
COG: 320 Grad, SOG: 0.23 kn
COG: 320 Grad, SOG: 0.23 kn
COG: 320 Grad, SOG: 0.23 kn
Breite: 54.26037 Grad, Laenge: 10.08289 Grad, Hoehe: 42.9m, Sats: 7
COG: 320 Grad, SOG: 0.23 kn
COG: 242 Grad, SOG: 0.25 kn
COG: 242 Grad, SOG: 0.25 kn
COG: 242 Grad, SOG: 0.25 kn

Der Plotter mit eingebautem GPS, steht bei mir vor dem Fenster und hat so einen brauchbaren Empfang mit 5-8 Satelliten. Kurs und Geschwindigkeit springen aber etwas um die eigentlich feste Position herum. Das ist einfach der Positionsfehler und gut in den Daten zu sehen.

Hier der Aufbau:

NMEA2000 position read

Verwendet wurden:

Arduino Software 1.6.5
Die Library von Timo Lappalainen
Arduino Mega 2560
MCP2515 & TJA1050 Platine
Ein NMEA2000 Netzwerk mit Stromversorgung und Abschlußwiderständen
Lowrance HDS 5m Plotter mit NMEA2000 Ausgang
Verbindungen wie hier beschrieben

von Matthias Busse

4 Gedanken zu „NMEA2000 GPS-Position in den Arduino einlesen und formatiert ausgeben

  1. Robert

    Hallo Mathias,
    die beiden defins:
    #define N2k_CAN_INT_PIN 21
    #define MCP_CAN_RX_BUFFER_SIZE 100
    müssen vor den
    #include
    stehen, sonst hat das keine wirkung.

    Antworten
  2. Bernhard

    Hallo Mathias,

    gibt es eine Möglichkeit die Anzahl der Nachkommastellen beim Längen- und Breitengrad zu erhöhen, damit Positionsbestimmungen im Zentimeterbereich möglich werden?

    Vielen Dank.

    Antworten

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.