Navigazione GPS: interpretare le stringhe NMEA-0183

Interpretare le stringhe NMEA-0183 dei navigatori GPS. TEA: un semplice ma efficace algoritmo di encryption. Un orologio/datario con Atmel AT89C4051.

Navigazione GPS: interpretare le stringe NMEA-0183

Un ricevitore GPS può essere facilmente interfacciato con qualsiasi microcontrollore  attraverso l’UART. La lettura delle stringhe inviate dal ricevitore e basate sul protocollo  NMEA 0183 è invece una cosa leggermente più complicata soprattutto se non è noto il formato dei dati. Il listato 1 riporta alcune routine per PIC (i sorgenti sono in C per il compilatore Hitech) utili per la lettura delle stringhe NMEA 0183  ed il calcolo di  distanze e molti  altri parametri di navigazione. Il listato 2 riporta integralmente il file .h contenente le dichiarazioni delle funzioni.

#include <pic18.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "nmea.h"
#ifndef M_PI
#define M_PI ((double) 3.14159265358979)
#endif

void nmea_gprmc(_const char *line);
void nmea_gpgga(_const char *line);
struct nmea_gps_data gps_data;
char nmea_handle_line(_const char *line)
{
  if(line[0] == '$' && line[1] == 'G' && line[2] == 'P')
    {
       if(line[3] == 'R' && line[4] == 'M' && line[5] == 'C') // GPRMC
         {
           nmea_gprmc(line);
           return NMEA_GPRMC;
         }
       else
         ;
    }
  return 0;
}

//esempio:
// $GPRMC,142455,V,3900.0000,N,09500,0000,W,000.0,000.0,010105,003.8,E*78
// 0000000000111111111122222222223333333333444444444455555555556666666666
// 0123456789012345678901234567890123456789012345678901234567890123456789
extern bit active;
void nmea_gprmc(_const char *line)
{ memcpy(gps_data.time, line+7, sizeof(gps_data.time));
  memcpy(gps_data.date, line+53, sizeof(gps_data.date));
  memcpy(gps_data.latitude, line+16, sizeof(gps_data.latitude));
  memcpy(gps_data.longitude, line+28, sizeof(gps_data.longitude));
  memcpy(gps_data.velocity, line+41, sizeof(gps_data.velocity));
  memcpy(gps_data.heading, line+47, sizeof(gps_data.heading));
  active = (*(line+14)=='A'?1:0);

  return;
}
void nmea_copy_to_logdata(struct nmea_gps_logdata *to)
{
  memcpy(to->date, gps_data.date, sizeof(to->date));
  memcpy(to->time, gps_data.time, sizeof(to->time));
  memcpy(to->latitude, gps_data.latitude, sizeof(to->latitude));
  memcpy(to->longitude, gps_data.longitude, sizeof(to->longitude));

  return;
}

//conversione delle coordinate:
double nmea_coordinate_to_double(_const char *str)
{
  unsigned char intpart;
  char tmpstr[sizeof(gps_data.longitude) + 1];

  if(str[5] == '.') // longitudine
    {
      memcpy(tmpstr, str+3, sizeof(gps_data.longitude)-3);
      tmpstr[sizeof(gps_data.longitude)-3] = '\0';
      intpart = (str[0]-'0')*100 + (str[1]-'0')*10 + (str[2]-'0');
    }
  Else //latitudine
    {
      memcpy(tmpstr, str+2, sizeof(gps_data.latitude)-2);
      tmpstr[sizeof(gps_data.latitude)-2] = '\0';
      intpart = (str[0]-'0')*10 + (str[1]-'0');
     }

  return intpart + atof(tmpstr)/60;
}

double nmea_distance(struct nmea_position *one, struct nmea_position *two)
{
  // da longitudine (in gradi) a km:
  // cos(latitudine/360 * 2*M_PI) * 40070 / 360 =
  // cos((double) 2*M_PI/360 * latitudine) * ((double) 40070/360)

  double difflat, difflong;

  difflat = (two->latitude - one->latitude) * (double) 111000;
  difflong = (two->longitude - one->longitude) * (double) 49142;

  return sqrt(difflat*difflat + difflong*difflong);
}

signed short nmea_bearing(struct nmea_position *one, struct nmea_position *two)
{
  double difflat, difflong;
  double rads;
  signed short degs;

  difflat = (two->latitude - one->latitude) * (double) 111000; // y
  difflong = (two->longitude - one->longitude) * (double) 49142; // x

  rads = atan2(difflat, difflong);
  rads = -(rads - M_PI/2); // twist and mirror to fit GPS coordinates

  degs = (double) 360 * rads / (M_PI*2) -
         ((gps_data.heading[0]-'0') * 100 + (gps_data.heading[1]-'0') * 10 + (gps_data.heading[2]-'0'));

if(degs > 180)
  degs-=360;
else if(degs < -180)
  degs+=360;

  return degs;
}
Listato 1
#ifndef _NMEA_H
#define _NMEA_H

#define NMEA_GPRMC 1

char nmea_handle_line(_const char *line);
void nmea_copy_to_logdata(struct nmea_gps_logdata *to);
double nmea_coordinate_to_double(_const char *str);
double nmea_distance(struct nmea_position *one, struct nmea_position *two);
signed short nmea_bearing(struct nmea_position *one, struct nmea_position *two);

struct nmea_gps_data
  {
    char time[6];
    char date[6];
    char latitude[9];
    char longitude[10];
    char heading[3];
    char velocity[5];
  };

struct nmea_gps_logdata
  {
    char time[6];
    char date[6];
    char latitude[9];
    char longitude[10];
  };

struct nmea_position
  {
    double latitude;
    double longitude;
  };

#define NMEA_OFFSET 20
#define NMEA_POS_OFFSET(x) ((sizeof(struct nmea_gps_logdata)*x) + NMEA_OFFSET)

extern struct nmea_gps_data gps_data;

#endif
Listato 2

Una risposta

  1. Daniele Facchin 21 marzo 2016

Scrivi un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *