парсинг NMEA

gzp13
Offline
Зарегистрирован: 06.04.2015

Здравствуйте, подскажите, как мне из определенной строки вытащить необходимые мне данные. Есть два сообщения, $GPGGA и $GPRMC, мне нужно из сообщения GPGGA вытащить седьмое число после запятой,т.е кол-во спутников, а из сообщения GPRMC вытащить скорость, что является тоже седьмым числом после запятой.Как распознать тип сообщения я вроде как сообразил.Вот код.

#include <SoftwareSerial.h>
SoftwareSerial mySerial(4, 3); // RX, TX

 char st = '0';
char b;
boolean renew = false;
 
void setup() {
  Serial.begin(9600);
  mySerial.begin(9600);
 }
void loop()
{
char b = mySerial.read();
 
switch ( st ) // перебираем состояния
{
case '0': if('$' == b) st = '1';
break;
case '1': if('G' == b) st = '2'; else st = '0';
break;
case '2': if('P' == b) st = '3'; else st = '0';
break;
case '3': if('G' == b) st = '4'; else st = '0';
break;
case '4': if('G' == b) st = '5'; else st = '0';
break;
case '5': if('A' == b) st = '6'; else st = '0';
break;
case '6': if(',' == b) { // распознали $GPGGA
st = '0';
}
breake;
}

Не знаю правильно так или нет, но работает. А вот дальше загвоздка, как теперь посчитать семь запятых в этих сообщениях?

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015
gzp13
Offline
Зарегистрирован: 06.04.2015

а на каких скоростях работает библиотека? На 9600 слишком медленно, пробовал пделать на библиотеке TINYGPS+, очень медленно информация поступает из ардуины. Мне надо чтобы она принимала с GPS по UART на скорости 57600(5 раз в секунду), а эта библиотека работает на 9600.

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

она не работает с портом, данные вы читаете сами, она только парсит строку на составляющие.

скорость зависит от приемника, некоторые умеют перенастаиваться.

для приёмника BU-353 GLONASS, ND105C

Команда изменения частоты на 10 ГЦ (десять раз в секунду): $PMTK220,100*2F

Команда изменения частоты на 5 ГЦ (пять раз в секунду):  $PMTK220,200*2C

Максимальная частота фиксации координат для данного GPS-чипсета 10 ГЦ.

 

gzp13
Offline
Зарегистрирован: 06.04.2015

ясно, спасибо за наводку. Только я не очень понимаю как ею пользоваться. Это же не библиотека, просто скопировать код и вставить в пой скетч, а дальше выбрать необходимые мне параметры для расшифровки?

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

как включать читайте тут на форуме, мне лень расписывать все это, да хоть что-то вы должны сделать  :)

пример про скорость там-же https://github.com/ericbarch/arduino-libraries/blob/master/NMEA/examples/gprmc_speed/gprmc_speed.pde

gzp13
Offline
Зарегистрирован: 06.04.2015

Не пойму как этим добром пользоваться.Тупо скопировал все, потом ниже ставлю свой код.

#ifndef nmea_h
#define nmea_h

#include "Arduino.h"
#include <SoftwareSerial.h>
SoftwareSerial ss(4,3);

#define  ALL         0               // connect to all datatypes
#define GPRMC       1               // connect only to GPRMC datatype
#define MTR         1.0             // meters per meter
#define KM          0.001           // kilometers per meter
#define MI          0.00062137112   // miles per meter
#define NM          0.00053995680   // nautical miles per meter
#define PARSEC      0.000000000000  // parsecs per meter (approximation)
#define MPS         0.51444444      // meters-per-second in one knot
#define KMPH        1.852           // kilometers-per-hour in one knot
#define MPH         1.1507794       // miles-per-hour in one knot
#define KTS         1.0             // knots in one knot
#define LIGHTSPEED  0.000000001716  // lightspeeds in one knot


class NMEA
{
  public:
    NMEA(int connect);          // constructor for NMEA parser object; parse sentences of GPRMC or all datatypes.
    int   decode(char c);       // parse one character received from GPS; returns 1 when full sentence found w/ checksum OK, 0 otherwise
    float gprmc_utc();          // returns decimal value of UTC term in last full GPRMC sentence
    char  gprmc_status();       // returns status character in last full GPRMC sentence ('A' or 'V')
    float gprmc_latitude();     // signed degree-decimal value of latitude terms in last full GPRMC sentence
    float gprmc_longitude();    // signed degree-decimal value of longitude terms in last full GPRMC sentence
    float gprmc_speed(float unit);  // speed-on-ground term in last full GPRMC sentence
    float gprmc_course();       // track-angle-made-good term in last full GPRMC sentence
    float gprmc_distance_to(float latitude, float longitude, float unit); // returns distance from last-known GPRMC position to given position
    float gprmc_course_to(float latitude, float longitude);     // returns initial course in degrees from last-known GPRMC position to given position   
    char* sentence();           // returns last received full sentence as zero terminated string
    int   terms();              // returns number of terms (including data type and checksum) in last received full sentence
    char* term(int t);          // returns term t of last received full sentence as zero terminated string
    float term_decimal(int t);  // returns the base-10 converted value of term[t] in last full sentence received
    int   libversion();         // returns software version number of NMEA library
  private:
    // properties
    int   _gprmc_only;
    float _gprmc_utc;
    char  _gprmc_status;
    float _gprmc_lat;
    float _gprmc_long;
    float _gprmc_speed;
    float _gprmc_angle;
    char  f_sentence[100];
    char* f_term[30];
    int   f_terms;
    int   _terms;
    char  _sentence[100];
    char* _term[30];
    int   n;
    int   _gprmc_tag;
    int   _state;
    int   _parity;
    int   _nt;
    float _degs;
    // methods
    float distance_between (float lat1, float long1, float lat2, float long2, float units_per_meter);
    float initial_course(float lat1, float long1, float lat2, float long2);
    int   _dehex(char a);
    float _decimal(char* s);
};

#endif

void setup() {
Serial.begin(9600); // устанавливаем последовательное соединение
 ss.begin(9600);
}
void loop()
{
if(ss.available())
{
  Serial.print(_gprmc_utc);
}
}

При компиляции выдает ошибку _gprmc_utc was not declareted in this scope.

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

Мда... Три года на форуме и до сих пор не научились пользоваться гитхабом и подключать библиотеки.

renoshnik
Offline
Зарегистрирован: 11.04.2013
gzp13
Offline
Зарегистрирован: 06.04.2015

Ну библиотеку подключить не сложно если она в ZIP архиве, а в таком виде я даже и не знаю как ее задействовать.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Жесть - это такая холоднокатаная листовая сталь с защитным покрытием, сделаная по ГОСТ Р 52204-2004

renoshnik
Offline
Зарегистрирован: 11.04.2013

gzp13 пишет:

Ну библиотеку подключить не сложно если она в ZIP архиве, а в таком виде я даже и не знаю как ее задействовать.

зачем тебе библиотека ???  я тебе нормальную ссылку дал, там человек все разжевал уже дальше некуда...

gzp13
Offline
Зарегистрирован: 06.04.2015

так, разобрался, выводит то что надо. Но тут выводится информация только из сообщения GPRMC, а мне надо еще кол-во спутников, которое зашифровано в сообщении GPGGA. Как быть?)

renoshnik
Offline
Зарегистрирован: 11.04.2013

gzp13 пишет:

так, разобрался, выводит то что надо. Но тут выводится информация только из сообщения GPRMC, а мне надо еще кол-во спутников, которое зашифровано в сообщении GPGGA. Как быть?)

даже НЕ смешно ...

gzp13
Offline
Зарегистрирован: 06.04.2015

не ну правда, я не спец по работе с GPS,можно извлечь как то кол-во спутников? Оно зашифровано в GPGGA.

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

не ну ты прикалываешься что-ли? я тоже не спец, по второй ссылке в гугле находится

$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47
где:
GGA – NMEA Заговолок
123519 –UTC время 12:35:19
4807.038, N – Широта, 48 градусов 7.038 минуты северной широты
01131.000, Е – Долгота, 11 градусов 31.000 минуты восточной долготы
1 - тип решение, StandAlone решение
0 – нет решения,
1 – StandAlone,
2 – DGPS,
3 – PPS,
4 – фиксированный RTK,
5 – не фиксированный RTK,
6 – использование данных инерциальных систем,
7 – ручной режим,
8 – режим симуляции
08 – количество используемых спутников
0.9 – геометрический фактор, HDOP
545.4, М – высота над уровнем моря в метрах
46.9, М – высота геоида над эллипсоидом WGS 84
[пустое поле] – время прошедшее с момента получения последней DGPS
поправки. Заполняется при активизации DGPS режима
[пустое поле] – идентификационный номер базовой станции. Заполняется при
активизации DGPS режима.

 

gzp13
Offline
Зарегистрирован: 06.04.2015

да это я згаю, как мне применив вот это https://github.com/ericbarch/arduino-libraries/tree/master/NMEA получить кол-во спутников. Как я понял эта библиотека расшифровывает только строку GPRMC, или я не прав?

renoshnik
Offline
Зарегистрирован: 11.04.2013

gzp13 пишет:

да это я згаю, как мне применив вот это https://github.com/ericbarch/arduino-libraries/tree/master/NMEA получить кол-во спутников. Как я понял эта библиотека расшифровывает только строку GPRMC, или я не прав?

 

тоесть ту ссылку, что я дал ты упорно читать не хочешь...

 

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

да... это именно сталь с защитным покрытием :(

gzp13
Offline
Зарегистрирован: 06.04.2015

constructor for NMEA parser object; parse sentences of GPRMC or all datatypes. Вот что там написано, я так понимаю только для GPRMC.

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

«Жесть» — дебютный фильм петербургского кинорежиссёра Дениса Нейманда 2006 года по сценарию Константина Мурзенко в жанре психологического триллера.  

Вот это ближе к теме и ближе к триллеру

gzp13
Offline
Зарегистрирован: 06.04.2015
NMEA(int connect);					// constructor for NMEA parser object; parse sentences of GPRMC or all datatypes.
		int		decode(char c);				// parse one character received from GPS; returns 1 when full sentence found w/ checksum OK, 0 otherwise
		float	gprmc_utc();					// returns decimal value of UTC term in last full GPRMC sentence
		char	gprmc_status();				// returns status character in last full GPRMC sentence ('A' or 'V')
		float	gprmc_latitude();			// signed degree-decimal value of latitude terms in last full GPRMC sentence
		float	gprmc_longitude();		// signed degree-decimal value of longitude terms in last full GPRMC sentence
		float	gprmc_speed(float unit);	// speed-on-ground term in last full GPRMC sentence
		float	gprmc_course();				// track-angle-made-good term in last full GPRMC sentence
		float	gprmc_distance_to(float latitude, float longitude, float unit);	// returns distance from last-known GPRMC position to given position
		float gprmc_course_to(float latitude, float longitude);			// returns initial course in degrees from last-known GPRMC position to given position		
		char*	sentence();						// returns last received full sentence as zero terminated string
		int		terms();							// returns number of terms (including data type and checksum) in last received full sentence
		char*	term(int t);					// returns term t of last received full sentence as zero terminated string
		float	term_decimal(int t);	// returns the base-10 converted value of term[t] in last full sentence received
		int		libversion();					// returns software version number of NMEA library

Нет тут кол-ва спутников.

gzp13
Offline
Зарегистрирован: 06.04.2015

И все умники замолчали.

renoshnik
Offline
Зарегистрирован: 11.04.2013

gzp13 пишет:

И все умники замолчали.

А, хренли тебе писать когда ты сам с собой болтаешь ...

 

renoshnik
Offline
Зарегистрирован: 11.04.2013
Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

gzp13 пишет:

Как быть?)

Купить хороший аудиопровод из безкислородной меди, и повеситься на нём нахрен от такой жизни.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

ИЧСХ, тема называется "парсинг NMEA". А внутри - поиск быдлотек(тм) чужими руками :)

gzp13
Offline
Зарегистрирован: 06.04.2015

Полазив по форуму, нашел код, переделал неиного, все работает, но слишком медленно, частота обновления информации 1сек, а мне надо выводить 5 раз в секунду. Код такой.

#include <SoftwareSerial.h>
static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 57600;
SoftwareSerial ss(RXPin, TXPin);



void setup(void) {
Serial.begin(9600);
  ss.begin(GPSBaud);
}


//
// Эта функция принимает символ из Serial и возвращает
//  указатель на полученную строку или NULL, если строка
//  ещё не получена.
// Строка всегда начинается с $ и заканчивается \r или \n
//
static const int MAX_LEN = 140; // 120 - максимальная длина строки - надо посмотреть правильное значение в описании протокола!

char * getStrFromSerial(void) {
  static bool waitingForStrBegin = true; // истина, если мы ждём начала строки ($)
  static char strBuf[MAX_LEN];  // буфер для строки
  static int ptr = 0; // индекс свободного байта в буфере

  //
  //  Если буфер переполнился, печатаем сообщение и начинаем ждать новую строку
  //
  if (ptr >= MAX_LEN) {
    Serial.println("*** Error: Too long string!!!");
    ptr = 0;
    waitingForStrBegin = true;
    return NULL;
  }
  //
  //  Если в Serial ничего нет - выходим
  //  А если есть, то читаем 1 символ
  //
  if (!ss.available()) return NULL;
  const char c = ss.read();
  //
  //  Если мы ждём начала строки, то сравинваем 
  //  прочитанный символ с '$', если равен - начало найдено
  //
  if (waitingForStrBegin) {
    if (c == '$') {
      ptr = 0;
      strBuf[ptr++] = c;
      waitingForStrBegin = false;
    } 
    return NULL;
  }
  //
  //  Если прочитанный символ - перевод строки или возврат каретки
  //  то считаем, что строка закончилась. Возвращаем её,
  // а сами готовимся ждать новую.
  //
  if (c == '\r' || c == '\n') {
    strBuf[ptr] = '\0';
    waitingForStrBegin = true;
    return strBuf;
  }
  //
  //  Просто записываем символ в строку
  //
  strBuf[ptr++] = c;
  return NULL;
}

//
//  Читаeм долготу и широту, складывает в lon и lat
// Возвращает true, если прочитала и false если нет
//
bool readLatLon( int & num_sat) {
  // 
  //  getStrFromSerial() вернёт строку, полученную из Serial
  // или NULL, если строка ещё пока не получена
  //
  const char * str = getStrFromSerial();
  //
  //  Если строка ещё не получена, выходим
  //
  if (str == NULL) return false;
  //
  //  Если строка не начинается с "$GPGGA",
  // то она нам не нужна выходим
  //
  const char * prefix = "$GPGGA";
  if (strncmp(str, prefix, strlen(prefix))) return false;
  //
  //  Ищем первую запятую в строке str
  //
   char * comma = strchr(str, ',');
  //
  //  Если не нашли (строка кривая пришла?) - выходим
  //
  if (!comma) return false;
  //
  //  со следующего символа просле запятой идёт числоа - широта
  //
  
  //
  //  Ищем вторую запятую после начала числа-широты
  //
  comma = strchr(comma+1, ','); // сначала ищем первую запятую 2
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // теперь ищем вторую запятую 3
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // сначала ищем первую запятую 4
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // сначала ищем первую запятую 5
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // сначала ищем первую запятую 6
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // сначала ищем первую запятую 7
  if (!comma) return false; // почему-то не нашли :((((
  num_sat = atoi(comma+1);
  //
  //  Вроде всё
  //
  return true;
}
bool readspeed(int & speed, double & time) {
  // 
  //  getStrFromSerial() вернёт строку, полученную из Serial
  // или NULL, если строка ещё пока не получена
  //
  const char * str = getStrFromSerial();
  //
  //  Если строка ещё не получена, выходим
  //
  if (str == NULL) return false;
  //
  //  Если строка не начинается с "$GPRMC",
  // то она нам не нужна выходим
  //
  const char * prefix = "$GPRMC";
  if (strncmp(str, prefix, strlen(prefix))) return false;
  //
  //  Ищем первую запятую в строке str
  //
   char * comma = strchr(str, ',');
  //
  //  Если не нашли (строка кривая пришла?) - выходим
  //
  if (!comma) return false;
  //
  //  со следующего символа просле запятой идёт числоа - широта
  //
  time = atof(comma+1);
  //
  //  Ищем вторую запятую после начала числа-широты
  //
  comma = strchr(comma+1, ','); // сначала ищем первую запятую 2
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // теперь ищем вторую запятую 3
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // сначала ищем первую запятую 4
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // сначала ищем первую запятую 5
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // сначала ищем первую запятую 6
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // сначала ищем первую запятую 7
  if (!comma) return false; // почему-то не нашли :((((
  speed = atoi(comma+1);
  //
  //  Вроде всё
  //
  return true;
}
void loop(void) {
  //
  // Широта и долгота
  //
  int  num_sat;
  int speed;
  double time;
  // Читаем широту и долготу и если успешно прочитались, печатаем
  //
  if (readLatLon( num_sat)) {
    //Serial.print("Latitude: ");
    //Serial.println(lat, 5);
    Serial.print("num_sat: ");
    Serial.println(num_sat);
  }
   if (readspeed( speed, time)) {
    Serial.print("time: ");
    Serial.println(time, 2);
    Serial.print("speed: ");
    Serial.println(speed);
}
}

Запуская вот этот код, информация выводится как положено, каждые 200мс.

#include <SoftwareSerial.h>
SoftwareSerial ss(4,3);
char incomingByte;
void setup() {
Serial.begin(9600); // устанавливаем последовательное соединение
 ss.begin(57600);
}


void loop(){
if(Serial.available())ss.write(Serial.read());
if(ss.available())Serial.write(ss.read());
}

Я так понимаю, первый код слишком тяжелый, задача всего то вывести 2 параметра из двух строк от GPS приемника.Может кто что подскажет по оптимизации? Пробовал библиотеку NMEA, она глючит с моим OLED дисплеем, как только прописываю  строки         #include <nmea.h> и NMEA gps(GPRMC) дисплей не запускается. Поэтому прихожу к тому, что строки эти надо вручную обрабатывать, проверить пришла ли нужная строка и вытаскивать необходимое значение, причем число типа int.

 

b707
Offline
Зарегистрирован: 26.05.2017

и что - неужели при такой вот передаче параметров последующий принт печатает ненулевые значения num_sat, time  и speed? - не верю

if (readLatLon( num_sat)) {
    //Serial.print("Latitude: ");
    //Serial.println(lat, 5);
    Serial.print("num_sat: ");
    Serial.println(num_sat);
  }
   if (readspeed( speed, time)) {
    Serial.print("time: ");
    Serial.println(time, 2);
    Serial.print("speed: ");
    Serial.println(speed);
}

может вы ошиблись при выкладывании скетча в конфу? - не должно это работать

gzp13
Offline
Зарегистрирован: 06.04.2015

Нет не ошибся, передает каждые 200мс. Не знаю как картинку приложить.

gzp13
Offline
Зарегистрирован: 06.04.2015

renoshnik
Offline
Зарегистрирован: 11.04.2013

Это уже оцинкованая жесть !!!

gzp13 пишет:

Полазив по форуму, нашел код, переделал неиного, все работает, но слишком медленно, частота обновления информации 1сек, а мне надо выводить 5 раз в секунду. Код такой.

********

== Какой нафиг "полазив по форуму" ?  Эту ссылку я тебе тут два дня назад дал !

пост#8

gzp13 пишет:

Запуская вот этот код, информация выводится как положено, каждые 200мс.

********

Я так понимаю, первый код слишком тяжелый, задача всего то вывести 2 параметра из двух строк от GPS приемника.Может кто что подскажет по оптимизации? 

=== Все нормально работает скетч !!!

Когда себя прооптимизируешь, то может поймешь, что модуль отдает информацию с частотй 1 Гц, а если нужно быстрее, то нужно перепрограммировать сам модуль !

пост#3

но жесть крепка и не пробиваема ...

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

gzp13 пишет:

нашел код, переделал неиного, все работает

Так, ну я не буду комментировать как Вы его изуродовали переделали, только "работает" он у Вас "как повезёт". Повезёт - найдёт строку, не повезёт - пропустит. Нормально сработает только в том случае, если $GPGGA будет чётной строкой, а $GPRMC - нечётной. Если чётность не такая - она пропустит соответсвующие строки.

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

b707 пишет:

и что - неужели при такой вот передаче параметров последующий принт печатает ненулевые значения num_sat, time  и speed? 

Там же ссылки.

gzp13
Offline
Зарегистрирован: 06.04.2015

Модуль я перепрошил на частоту 5Гц, он работает, данные на этой частоте приходят как и положено, в мониторе порта это хорошо видно.

renoshnik
Offline
Зарегистрирован: 11.04.2013

gzp13 пишет:

Модуль я перепрошил на частоту 5Гц, он работает, данные на этой частоте приходят как и положено, в мониторе порта это хорошо видно.

пост #32  прочитай, посмотри как идут строки, подумай, прими решение .

(поменяй очередность запросов в лупе)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

renoshnik пишет:

(поменяй очередность запросов в лупе)

Ох, напрасно Вы так! Он ведь посчитает, что это должно решить проблему и ... в общем, нехорошо о Вас подумает :)

b707
Offline
Зарегистрирован: 26.05.2017

ЕвгенийП пишет:

b707 пишет:

и что - неужели при такой вот передаче параметров последующий принт печатает ненулевые значения num_sat, time  и speed? 

Там же ссылки.

Чувствую. что мне надо это повторить... Чета казалось, что если параметр функции - ссылка, то и передавать надо ссылки, а не переменные

gzp13
Offline
Зарегистрирован: 06.04.2015
Нормально сработает только в том случае, если $GPGGA будет чётной строкой, а $GPRMC - нечётной. Если чётность не такая - она пропустит соответсвующие строки.

Вы правы, выводится 2 раза кол-во спутников, поэтому и не работает на нужной частоте 5Гц. Но что можно предпринять для выхода из этой ситуации?

renoshnik
Offline
Зарегистрирован: 11.04.2013

ЕвгенийП пишет:

renoshnik пишет:

(поменяй очередность запросов в лупе)

Ох, напрасно Вы так! Он ведь посчитает, что это должно решить проблему и ... в общем, нехорошо о Вас подумает :)

тогда я расстроюсь и сделаю себе харакири   :-))  

но похоже он это так и не попробывал сделать...  тупо долбится с двойным выводом спутников ...  

а то убралсябы один лишний вывод спутников, глядишь и с частотой наладилось ... пока наладилось бы ...

 

b707
Offline
Зарегистрирован: 26.05.2017

gzp13 пишет:

Нормально сработает только в том случае, если $GPGGA будет чётной строкой, а $GPRMC - нечётной. Если чётность не такая - она пропустит соответсвующие строки.

Вы правы, выводится 2 раза кол-во спутников, поэтому и не работает на нужной частоте 5Гц. Но что можно предпринять для выхода из этой ситуации?

например искать $GPRMC и $GPGGA в одной и той же функции. В начале функции проверяем, с чего начинается строка - и в зависимости от результата извлекаем либо то, либо другое. Заодно и дублирования своего жуткого кода с поиском запятых избавитесь

gzp13
Offline
Зарегистрирован: 06.04.2015

Вы имеете ввиду поменять порядок строк с переменными int speed,int num_sat и double time ?

Не злитесь, ну не спец я в этом парсинге, понимаю как должно быть, а реализовать не могу. 

b707
Offline
Зарегистрирован: 26.05.2017

gzp13 - при ответе либо начинайте ответ с имени собеседника, либо цитируйте часть сообщения, на которое отвечаете.

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Никто особо и не злится, а ответ на твой вопрос "что делать" см. в посте #24. Там всё написано.

gzp13
Offline
Зарегистрирован: 06.04.2015

Хорошо, идею я понял. Как мне в данном коде реализовать проверку приходящтх строк в одной функции .


#include <SoftwareSerial.h>
static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 57600;
SoftwareSerial ss(RXPin, TXPin);



void setup(void) {
Serial.begin(9600);
  ss.begin(GPSBaud);
}


//
// Эта функция принимает символ из Serial и возвращает
//  указатель на полученную строку или NULL, если строка
//  ещё не получена.
// Строка всегда начинается с $ и заканчивается \r или \n
//
static const int MAX_LEN = 140; // 120 - максимальная длина строки - надо посмотреть правильное значение в описании протокола!

char * getStrFromSerial(void) {
  static bool waitingForStrBegin = true; // истина, если мы ждём начала строки ($)
  static char strBuf[MAX_LEN];  // буфер для строки
  static int ptr = 0; // индекс свободного байта в буфере

  //
  //  Если буфер переполнился, печатаем сообщение и начинаем ждать новую строку
  //
  if (ptr >= MAX_LEN) {
    Serial.println("*** Error: Too long string!!!");
    ptr = 0;
    waitingForStrBegin = true;
    return NULL;
  }
  //
  //  Если в Serial ничего нет - выходим
  //  А если есть, то читаем 1 символ
  //
  if (!ss.available()) return NULL;
  const char c = ss.read();
  //Serial.print(c);
  //
  //  Если мы ждём начала строки, то сравинваем 
  //  прочитанный символ с '$', если равен - начало найдено
  //
  if (waitingForStrBegin) {
    if (c == '$') {
      ptr = 0;
      strBuf[ptr++] = c;
      waitingForStrBegin = false;
    } 
    return NULL;
  }
  //
  //  Если прочитанный символ - перевод строки или возврат каретки
  //  то считаем, что строка закончилась. Возвращаем её,
  // а сами готовимся ждать новую.
  //
  if (c == '\r' || c == '\n') {
    strBuf[ptr] = '\0';
    waitingForStrBegin = true;
    return strBuf;
  }
  //
  //  Просто записываем символ в строку
  //
  strBuf[ptr++] = c;
  return NULL;
}

//
//  Читаeм долготу и широту, складывает в lon и lat
// Возвращает true, если прочитала и false если нет
//
bool readLatLon(double & time,double & num_sat, double & date  ) {
// 
  //  getStrFromSerial() вернёт строку, полученную из Serial
  // или NULL, если строка ещё пока не получена
  //
  const char * str = getStrFromSerial();
  //
  //  Если строка ещё не получена, выходим
  //
  if (str == NULL) return false;
  //
  //  Если строка не начинается с "$GNGLL",
  // то она нам не нужна выходим
  //
  const char * prefix = "$GPGGA";
  if (strncmp(str, prefix, strlen(prefix))) return false;
  //
  //  Ищем первую запятую в строке str
  //
   char * comma = strchr(str, ',');
  //
  //  Если не нашли (строка кривая пришла?) - выходим
  //
  if (!comma) return false;
  //
  //  со следующего символа просле запятой идёт числоа - широта
  //
  time = atof(comma+1);
  //
  //  Ищем вторую запятую после начала числа-широты
  //
 comma = strchr(comma+1, ','); // сначала ищем первую запятую 2
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // теперь ищем вторую запятую 3
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // сначала ищем первую запятую 4
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // теперь ищем вторую запятую 5
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // сначала ищем первую запятую 6
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // теперь ищем вторую запятую 7
  if (!comma) return false; // почему-то не нашли :((((
  //
  //  со следующего символа просле запятой идёт числоа - долгота
  //
  num_sat = atof(comma+1);
  //
  //  Вроде всё
  //
 
  return true;
}

void loop(void) {
  //
  // Широта и долгота
  //
  double time,num_sat, date;
  //
  // Читаем широту и долготу и если успешно прочитались, печатаем
  //
  if (readLatLon(time,num_sat, date)) {
    //Serial.print("time: ");
    Serial.println(time, 2);
    Serial.print("num_sat: ");
    Serial.println(num_sat, 0);
    Serial.print("date: ");
    Serial.println(date, 0);
  }
}

Я правильно записал строку 76?

Время и кол-во спутников извлекаем из строки &GPGGA. Это получилось. Теперь ине надо извлечь дату из строки GPRMC.

А вот как организовать проверку, что пришла строка &GPRMC? Я так понимаю нельзя в функцию bool readLatLon добавить условие проверки 

const char * prefix = "$GPGGA";
  if (strncmp(str, prefix, strlen(prefix))) return false;

Предполагаю, что встречаются одинаковые названия функций.

 

b707
Offline
Зарегистрирован: 26.05.2017

что мешает сделать вот так:


  const char * prefix = "$GPGGA";
  const char * prefix2 = "$GNGLL";
 
  if ( ! strncmp(str, prefix, strlen(prefix))) {
 
    // извлекаем данные из строки $GPGGA

  }
  else if  ( ! strncmp(str, prefix2, strlen(prefix2))) {
   
   // извлекаем данные из строки $GNGLL

  }
else return false;

 

 

gzp13
Offline
Зарегистрирован: 06.04.2015
что мешает сделать вот так:

 

Спасибо Вам b707, направили на нужную мысль, получилось то что я хотел. Всем большое спасибо за помощь.

gzp13
Offline
Зарегистрирован: 06.04.2015

так, возникла еще проблемка. Скорость с GPS поступает в узлах в час, знаю что для перевода в км/час надо скорость умножить на 1.852, т.е запись будет speed=atof(comma+1)*1.852

Но мой GPS занижает скорость на 4км/час, т.е мне надо прибавить еще 4км/час.Но тогда при нулевой скорости у меня на дисплее будет индицироваться 4км/час. Думаю что коррекцию скорости надо сделать после 30км/час, посмотрите код.Коррекция начинается со строки 173-184. Но при этих строках искажаются все данные на выходе(((


#include <SoftwareSerial.h>
static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 57600;
SoftwareSerial ss(RXPin, TXPin);
byte a=0;
byte b=0;


void setup(void) {
Serial.begin(9600);
  ss.begin(GPSBaud);
}


//
// Эта функция принимает символ из Serial и возвращает
//  указатель на полученную строку или NULL, если строка
//  ещё не получена.
// Строка всегда начинается с $ и заканчивается \r или \n
//
static const int MAX_LEN = 140; // 120 - максимальная длина строки - надо посмотреть правильное значение в описании протокола!

char * getStrFromSerial(void) {
  static bool waitingForStrBegin = true; // истина, если мы ждём начала строки ($)
  static char strBuf[MAX_LEN];  // буфер для строки
  static int ptr = 0; // индекс свободного байта в буфере

  //
  //  Если буфер переполнился, печатаем сообщение и начинаем ждать новую строку
  //
  if (ptr >= MAX_LEN) {
    Serial.println("*** Error: Too long string!!!");
    ptr = 0;
    waitingForStrBegin = true;
    return NULL;
  }
  //
  //  Если в Serial ничего нет - выходим
  //  А если есть, то читаем 1 символ
  //
  if (!ss.available()) return NULL;
  const char c = ss.read();
  //Serial.print(c);
  //
  //  Если мы ждём начала строки, то сравинваем 
  //  прочитанный символ с '$', если равен - начало найдено
  //
  if (waitingForStrBegin) {
    if (c == '$') {
      ptr = 0;
      strBuf[ptr++] = c;
      waitingForStrBegin = false;
    } 
    return NULL;
  }
  //
  //  Если прочитанный символ - перевод строки или возврат каретки
  //  то считаем, что строка закончилась. Возвращаем её,
  // а сами готовимся ждать новую.
  //
  if (c == '\r' || c == '\n') {
    strBuf[ptr] = '\0';
    waitingForStrBegin = true;
    return strBuf;
  }
  //
  //  Просто записываем символ в строку
  //
  strBuf[ptr++] = c;
  return NULL;
}

//
//  Читаeм долготу и широту, складывает в lon и lat
// Возвращает true, если прочитала и false если нет
//
bool readLatLon(double & time,double & num_sat, double & date , double & speed  ) 
{
// 

  //  getStrFromSerial() вернёт строку, полученную из Serial
  // или NULL, если строка ещё пока не получена
  //
  const char * str = getStrFromSerial();
  //
  //  Если строка ещё не получена, выходим
  //
  if (str == NULL) return false;
  //
  //  Если строка не начинается с "$GPGGA или GPRMC",
  // то она нам не нужна выходим
  //
  const char * prefix = "$GPGGA";
  const char * prefix2 = "$GPRMC";
 if (  ! strncmp(str, prefix, strlen(prefix))) 
  {
  //  Ищем первую запятую в строке str
  //
   char * comma = strchr(str, ',');
  //
  //  Если не нашли (строка кривая пришла?) - выходим
  //
  if (!comma) return false;
  //
  //  со следующего символа просле запятой идёт числоа - широта
  //
  time = atof(comma+1);
  //
  //  Ищем вторую запятую после начала числа-широты
  //
 comma = strchr(comma+1, ','); // сначала ищем первую запятую 2
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // теперь ищем вторую запятую 3
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // сначала ищем первую запятую 4
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // теперь ищем вторую запятую 5
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // сначала ищем первую запятую 6
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // теперь ищем вторую запятую 7
  if (!comma) return false; // почему-то не нашли :((((
  //
  //  со следующего символа просле запятой идёт числоа - долгота
  //
  num_sat = atof(comma+1);
 return true;
  }
  
  //  Вроде всё
  //
  
 else if  ( ! strncmp(str, prefix2, strlen(prefix2)))
 {
 char * comma = strchr(str, ',');
  //
  //  Если не нашли (строка кривая пришла?) - выходим
  //
  if (!comma) return false;
  //
  //  со следующего символа просле запятой идёт числоа - широта
  //
  time = atof(comma+1);
  //
  //  Ищем вторую запятую после начала числа-широты
  //
 comma = strchr(comma+1, ','); // сначала ищем первую запятую 2
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // теперь ищем вторую запятую 3
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // сначала ищем первую запятую 4
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // теперь ищем вторую запятую 5
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // сначала ищем первую запятую 6
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // теперь ищем вторую запятую 7
    if (!comma) return false; // почему-то не нашли :((((
    speed=atof(comma+1)*1.852;   // переводим скорость в км/час
    comma = strchr(comma+1, ','); // сначала ищем первую запятую 8
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // теперь ищем вторую запятую 9
  if (!comma) return false; // почему-то не нашли :((((
  date=atof(comma+1);
  //return true;
}
else return false;

}
void loop(void) {
  double time,num_sat, date,speed;
  
  if (speed>30 && a==0)   //выполняем коррекцтю скорости
   {                      //при скорости более 30км/час добавляем 3 км/час
speed=speed+3;            //и далее скорость растет на 1км/час 
a=1;                      //т.к приемник GPS занижает скорость на км/час 
b=0;
   }
  if (speed<29 && b==0)     // при скорости менее29 км/час 
   {                        // коррекцию убираем
        speed=speed-3; //чтобы при нулевой скорости на дисплее был нуль
b=1;
a=0;
   }
   
   //Читаем время,кол-во спутников,дату,скорость если успешно прочитались, печатаем
  
 if (readLatLon(time,num_sat, date,speed)) {
    Serial.print("time: ");
    Serial.println(time, 2);
    Serial.print("num_sat: ");
    Serial.println(num_sat, 0);
    Serial.print("date: ");
    Serial.println(date, 0);
    Serial.print("speed: ");
    Serial.println(speed, 0);
  }
 
}
renoshnik
Offline
Зарегистрирован: 11.04.2013

$GPVTG, x.x, T x.x, M x.x, N x.x, K *hh <CR><LF> 

1. Направление курса в градусах, T 

2. Магнитное склонение в градусах, М 

3. Скорость над поверхностью (SOG) в узлах, N = узлы 

4. Скорость над поверхностью (SOG) в км/ч, К = км/ч 

5. hh Контрольная сумма строки (обязательно) 

Пример сообщения: 

$GPVTG,217.5,T,208.8,M,000.00,N,000.01,K*4C 

 

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

gzp13 пишет:

Но мой GPS занижает скорость на 4км/час, т.е мне надо прибавить еще 4км/час.

чем измерено ? 

не спидометром автомобиля часом ?

gzp13
Offline
Зарегистрирован: 06.04.2015
не спидометром автомобиля часом ?

Именно им) Даже если и спидометр автомобиля завышает, все равно хотелось бы привести и ту и эту скорость к одной величине.