Помогите побороть GPS NEO-6M

svi
Offline
Зарегистрирован: 19.10.2017

Добрый всем вечер)

задача такова, генерировать частоту от скорости полученной из космоса :)

короче спидометр делаю

 

И так начеркал код как смог  с Arduino.ru и Google.ru на пару :)

#include <TinyGPS++.h>
#include <TimerOne.h>
#include <SoftwareSerial.h>
int output_Hz = 10;
int intput_Acc = 1;
int state_output_Hz = LOW;
int state_intput_Acc = LOW;
static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 19200;
TinyGPSPlus gps;
SoftwareSerial ss(RXPin, TXPin);

void setup()
{
  pinMode(output_Hz, OUTPUT);
  pinMode(intput_Acc, INPUT);
  Serial.begin(19200);
  ss.begin(GPSBaud);
}

void loop()
{
  Serial.println();
  
  printInt(gps.satellites.value(), gps.satellites.isValid(), 5);
  printFloat(gps.speed.kmph(), gps.speed.isValid(), 6, 2);
  
  if (gps.satellites.value()>=4 && gps.speed.kmph()>=1 /* && digitalRead(intput_Acc)==HIGH */)
  {
    int U = round(gps.speed.kmph());
    float W = 8.9*U;
    float T = (1.0/W)*1000000;
    Timer1.start();
    Timer1.initialize(T);
    Timer1.attachInterrupt(blinkLed);
  }
  else 
  {
    Timer1.stop();
    state_output_Hz = LOW;
  }
   smartDelay(100);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
static void smartDelay(unsigned long ms)
{
  unsigned long start = millis();
  do 
  {
    while (ss.available())
      gps.encode(ss.read());
  } while (millis() - start < ms);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
static void printFloat(float val, bool valid, int len, int prec)
{
  if (!valid)
  {
    while (len-- > 1)
      Serial.print('*');
    Serial.print(' ');
  }
  else
  {
    Serial.print(val, prec);
    int vi = abs((int)val);
    int flen = prec + (val < 0.0 ? 2 : 1); // . and -
    flen += vi >= 1000 ? 4 : vi >= 100 ? 3 : vi >= 10 ? 2 : 1;
    for (int i=flen; i<len; ++i)
      Serial.print(' ');
  }
  smartDelay(0);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
void blinkLed(){
  state_output_Hz = !state_output_Hz;
  digitalWrite(output_Hz, state_output_Hz);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
static void printInt(unsigned long val, bool valid, int len)
{
  char sz[32] = "*****************";
  if (valid)
    sprintf(sz, "%ld", val);
  sz[len] = 0;
  for (int i=strlen(sz); i<len; ++i)
    sz[i] = ' ';
  if (len > 0) 
    sz[len-1] = ' ';
  Serial.print(sz);
  smartDelay(0);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////

 и все вроде работает кроме одного но, слишком маленькая частота опроса GPS модуля (1Гц), для моего спидометра это мало. Как только не пытался увеличить частоту опроса не чего не выходит. В конце кода пауза в 100мс вроде имулирует опрос но 10 раз возвращает GPS модуль одни и те же значения))) (поодлюга)

скачал для это модуля программку для его настроек, лазил лазил и вроде нашел в настройках две частоты стояло в 1Hz я изменил на 5 Гц (где то в даташитах вычитал что модуль может выдавать до 5Гц), но не чего не получилось. Так и дает 10 значений одинаковых при паузе в 100мс, единственное чего добился это на плате GPS модуля светодиод сменил свою частоту вспышек с 1 до 5Гц :) (PPS)

Помоги люди умные мне бездарю, прошу не хаять. Ардуино 2 раз в руках держу. И правда 2 суток лазил в просторах интернета в поисках подсказок.

5N62V
Offline
Зарегистрирован: 25.02.2016

Вы в Ubloxe попробуйте отключить все лишние предложения,  там их по дефолту дофигища. А Вам достаточно только RMC. 

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

 

Ну и это, библиотека эта - еще то гавно. Для Вашей задачи она избыточна. Возьмите сырые данные по УАРТУ от модуля, да и выгрызите интересующую Вас переменную.

svi
Offline
Зарегистрирован: 19.10.2017

Спасибо что откликнулись на мой зов о помощи)

С сырыми данныеми не когда не работал. Почитал про устройство UART вроде будет не так сложно.

Не могли бы подсказать алгоритм действий работы с "сырыми" данными, а лучше последовательность функций подсказать. Что то вроде: инициализировать UART => считать данные => записать данные в буфер=> расшифровать нужный мне кусок из буфера ==> засунуть его в переменную.

На работе нашел кучу разных GPS/Глонасс модулей в готовых устройствах, посмотрел даташиты работают по UART все. Может еще с ними попробую повозиться если получиться напрямую из UART данные вытащить.

5N62V
Offline
Зарегистрирован: 25.02.2016

Если у вас будет приниматься только строка RMC, то тогда в бесконечно цикле:   есть данные в УАРТ? если да, то читаем и выбрасываем все пока не встретим символ $(начало строки) ,  после него читаем  строку и выбрасываем содержимое пока не встретится седьмая по счету запятая, после нее считываем float, все. :)  

https://ru.wikipedia.org/wiki/NMEA_0183

svi
Offline
Зарегистрирован: 19.10.2017

Спасибо буду пробовать, как что отпишусь.

svi
Offline
Зарегистрирован: 19.10.2017

Добрый день господа.

Вы не подумайте что я бросил свою затею :) Короче эпопея продолжается )))

Приехал ко мне долгожданный модуль с гордым названием GN-801, по отзывам на али экспрессе вроде хвалили и цена приемлемая. С этим модулем одну из своих задач решил, разогнал частоту опроса модуля до 5 Гц (То что нужно :) ). Но не все так гладко, теперь библиотека TinyGPS++ не хочет видеть количество спутников, а надо).

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

Для начала разберем, что хотим вообще "вытащить". А хотим скорость и количество спутников.

Что имеем:

13:10:21  $GNRMC,131021.40,V,,,,,,,180518,,,N*62

13:10:21  $GNVTG,,,,,,,,,N*2E

13:10:21  $GNGGA,131021.40,,,,,0,00,99.99,,,,,,*7C

13:10:21  $GNGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*2E

13:10:21  $GNGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*2E

13:10:21  $GPGSV,2,1,05,06,27,072,,09,19,054,,19,01,112,,23,14,017,*70

13:10:21  $GPGSV,2,2,05,29,43,282,*48

13:10:21  $GLGSV,2,1,08,68,05,005,,70,37,121,,71,03,158,,75,06,214,*6B

13:10:21  $GLGSV,2,2,08,76,34,253,,77,32,327,,78,01,005,,84,09,090,*6F

13:10:21  $GNGLL,,,,,131021.40,V,N*50

 

Это из программы u-center из поля TextConsole (я так понимаю что это и есть тот самый "пакет данных" в UART который я и заставил повторяться 5 раз в секунду.

Пользуясь вашими подсказками я понял что скорость в узлах это 7 число из строки  $GNRMC.

А  вот со количеством спутников непонятка какая то, но вроде 3 число из любой строки $GPGSV.

 

Подведем итог моих рассуждений:

1) Мне нужно 7 число из строки $GNRMC запихнуть в переменную Speed_kn

2) Мне нужно 3 чисто из строки $GPGSV запихнуть в переменную Satellite

 

Подскажите, как все же это сделать.

 

5N62V
Offline
Зарегистрирован: 25.02.2016

svi пишет:

Подведем итог моих рассуждений:

1) Мне нужно 7 число из строки $GNRMC запихнуть в переменную Speed_kn

2) Мне нужно 3 чисто из строки $GPGSV запихнуть в переменную Satellite

 

Подскажите, как все же это сделать.

 

Итог рассуждений правильный. Теперь стоит  составить алгоритм, и, не теряя времени, перейти к написанию кода программы. Сомневаюсь, что  кто-то будет писать код вместо Вас. Начать надо с организации приема данных по UART. То есть тот листинг, что Вы получили в uBlox, должен отображаться в мониторе порта Ардуино.

 

ПС. Отключите ненужные данные в uBlox. Оставьте только нужные Вам строки $GNRMC и $GPGSV.

svi
Offline
Зарегистрирован: 19.10.2017

Я понимаю что писать не кто не будет, просто я не могу найти информацию о том как "сканировать" строку и искать в ней нужное мне значение. Везде примеры с одним числом а не с строкой.
int incomingByte = 0; // переменная для хранения полученного байта

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

void loop() {
if (Serial.available() > 0) { //если есть доступные данные
// считываем байт
incomingByte = Serial.read();

// отсылаем то, что получили
Serial.print("I received: ");
Serial.println(incomingByte, DEC);
}
}
Вот пример с этого сайта, я так понял что считывается только первый байт. И в новом цикле опять первый байт и т.д. Или я не прав, как заставить идти дальше?!

5N62V
Offline
Зарегистрирован: 25.02.2016

Все правильно, только с чего Вы взяли, что считываемый байт является первым? Это просто текущий байт , а первый он, или еще какой - это предстоит выяснить.

Начало у Вас есть, и это уже гуд. Только просьба код вставлять как положено. 

Обращаю Ваше внимание на 2 момента:

1) скорость Вашего UART должна соответсвовать скорости, на которой модуль передает данные

2) Ваш модуль передает данные в текстовом формате согласно ASCII , поэтому прием надо организовывать соответсвующе.

Теперь что касается расшифровки данных: в NMEA протоколе признаком начала строки является знак $. То есть для того , чтобы начать расшифровывать строку, Вам надо вычитать и выбросить все пришедшие байты, пока не встретится код знака $.  Затем предстоит выяснить а какое же это предложение, $GNRMC или  $GPGSV, чтоб знать сколько запятых отсчитывать до интересующего значения. И только  тогда переходить к функции расшифровки.

Сама функция должна продолжить вычитывать пришедшие байты, подсчитывая количество байтов содержимое которых соответствует коду запятой.  Отсчитав нужное количество, функция должна считать следующие после запятой цифры и точку, превратить их в значение переменной и вернуть.  Вот и весь алгоритм. ;)

svi
Offline
Зарегистрирован: 19.10.2017

Спасибо! Сейчас приеду на работу буду пробовать, хотя так и не понял работу serial.read(), но думаю сначала попробую а там по рещультатам отпишусь.
P.s. по поволу кода извеняюсь, пишу с телефона. Крайне неудобно.

5N62V
Offline
Зарегистрирован: 25.02.2016

svi пишет:
Спасибо! Сейчас приеду на работу буду пробовать, хотя так и не понял работу serial.read(),

Читать:

http://arduino.ru/Reference/Serial/Read

Если и потом не понятно, то спрашивайте :)

svi
Offline
Зарегистрирован: 19.10.2017
#include <SoftwareSerial.h>
int data = 0;
SoftwareSerial mySerial(4, 3); // RX, TX

void setup() 
{
  Serial.begin(57600);
  while (!Serial) {}
  mySerial.begin(57600);
}

void loop() 
{
  if (mySerial.available() > 0) 
  {
    if (mySerial.read()== 36) // $
    {
      if (mySerial.read()== 71)  // G
      {
        if (mySerial.read()== 78)  // N
        {
          if (mySerial.read()== 82)  // R
          {
            if (mySerial.read()== 77)  // M
            {
              if (mySerial.read()== 67) // C
              {
                data = data + 1;
                Serial.println(data);
              }
            } 
          }
        }
      }
    }
  }
}

Написал для понимания принципа работы счетчик строк $GNRMC

И тут проблема, поидее в каждом пакете есть эта строка. Частота пакетов 5Гц. Значит я должен видеть обновления счетчика с той же частотой. Но это не так. Визуально на много меделее и как буд то иногда он пропускает.

Подскажите что не так?! И вообще сам принцип выделения строки нормальный? только до этого додумался пока что.

Short Circuit
Short Circuit аватар
Offline
Зарегистрирован: 17.05.2015

используете софт сериал?  он для этих целей глючный. советую на рх тх  проца подключить и попробовать. удивитесь.

Short Circuit
Short Circuit аватар
Offline
Зарегистрирован: 17.05.2015

да еще и 57600 выбрали..  с дуба упали ?:)   поставьте 9600 а еще лучше 2400, только нужно будет гпс модуль перенастроить на эту скорость. на 9600 софтсериал отдельные символы могу приниматься с ошибкой, на 2400 этого уже быть как бы не должно.

5N62V
Offline
Зарегистрирован: 25.02.2016

svi пишет:


Подскажите что не так?! И вообще сам принцип выделения строки нормальный? только до этого додумался пока что.

Во-первых, рекомендация не использовать софт сериал правильная. Софт сериал отлично передает, но плохо читает.

Во-вторых, надо понимать, что приход данных по уарт не есть мгновенным процессом. Смотрите , что вероятнее всего у Вас происходит: приходит байт, срабатывает условие в строке 14, проверка в строке 16 отсеит его, если это не $. А что будет , если пришел $? А будет вот что: программа немедленно считает еще один байт из уарта (строка 18) , не особо беспокоясь пришел ли он уже. И быть может вместо ожидаемых 71 вы получите в левой части оператора сравнения -1. Ибо нельзя с УАРТ считывать чаще, чем туда приходят байты.

Есть несколько вариантов выхода из положения. Например, ставить задержку перед каждым последующим считыванием. Сейчас меня заклюют, но delay(1); после каждого условия скорее всего решит Вашу проблему.

Или же поставить проверку, что новый байт появился в буфере. Это не есть блестящим решением, т.к. условие блокирующее, но вполне рабочее:

while(!Serial.available()); // тупо ждем, пока не появится новый байт

 

svi
Offline
Зарегистрирован: 19.10.2017

Short Circuit пишет:

да еще и 57600 выбрали..  с дуба упали ?:)   поставьте 9600 а еще лучше 2400, только нужно будет гпс модуль перенастроить на эту скорость. на 9600 софтсериал отдельные символы могу приниматься с ошибкой, на 2400 этого уже быть как бы не должно.


На скорости 57600 только работвет с частотрй 5гц

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

svi пишет:

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

void setup() 
{
  Serial.begin(57600);
  while (!Serial) {}
  mySerial.begin(57600);
}

void loop() 
{
  if (mySerial.available() > 0) 
  {
    if (mySerial.read()== 36) // $
    {
      if (mySerial.read()== 71)  // G
      {
        if (mySerial.read()== 78)  // N
        {
          if (mySerial.read()== 82)  // R
          {
            if (mySerial.read()== 77)  // M
            {
              if (mySerial.read()== 67) // C
              {
                data = data + 1;
                Serial.println(data);
              }
            } 
          }
        }
      }
    }
  }
}

Подскажите что не так?! И вообще сам принцип выделения строки нормальный? только до этого додумался пока что.

Общий принцип Вы в общем-то уловили, но в деталях реализации наделали ошибок.

1. 57600 для программного порта многовато, как справедливо отметили выше. 

2. Даже если взять 57600 - один байт будет приходить на этой скорости более 170 мкс, а контроллер за это время усеет сделать более 2500 операций. Сначала Вы терпеливо ждали, пока прийдет первый байт. Если этого не происходило, строка 14 по сути отправляла код на следу.ющую итерацию цткла. Но вот первый байт пришел: вы это определили в строке 14 и затем сразу же считали этот байт строкой 16. А вот дальше - проблема: Вы сразу жепытаетесь считать второй символ строкой 18, а его еще нет. Функция read - не блокирующая, т.е. она не останавливает код в ожидании очередного символа (и, кстати, правильно делает), но т.к. какой символ придет следующим она не знает, возвращает число, которое с точки зрения англоязычных разработчиков должно символизировать об ошибке, но которое в русском языке соответствует букве "я". Вот это "я" и получит Ваша 18-я строка, после чего цепочка разбора будет прервана и строку таким образом Вы потеряете.

3. Вы написали код, который вроде как должен разбирать строку. Пусть он и не работает должным образом, но у него есть еще очень большой недостаток - как только Вам понадобится разьирать другую строку, надо будет писать новый код.

 

Ну, что делать с п.1, надеюсь Вам объяснять не надо. А вот по поводу 2 и 3 - Вам надо почитать про конечные автоматы.

Ну а делать - примерно так: завести переменную, в которой будет помещаться количество совпавших символов. Каждый символ считывается только после mySerial.available на очередной итерации цикла. Т.е. читаем по одному символу, а не пытаемся прочесть сразу все. 

Получили очередной символ - проверяем, подходит ли он. Если подходит - увеличиваем счетчик на 1. Если не подходит - сбрасывавем счетчик в 0. Если увеличили - проверяем, не завершилась ли искомая строка. Если заершилась - предпринимаем предусмотренную реакцию.

При этом сразу очевидным образом получается реализация проверки одним и тем же кодом разный строк - путем сравнения с образцом.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

svi пишет:

На скорости 57600 только работвет с частотрй 5гц[/quote]

5 Гц или 5 кГц?

5N62V
Offline
Зарегистрирован: 25.02.2016

andriano пишет:

5 Гц или 5 кГц?

5Гц :)

svi
Offline
Зарегистрирован: 19.10.2017

Спасибо всем. Буду пробовать, как что толковое будет отпишусь.

svi
Offline
Зарегистрирован: 19.10.2017

И опять я)

написал я вот что

#include <SoftwareSerial.h>
int i = 0;
int s = 0;
SoftwareSerial mySerial(4, 3); // RX, TX

void setup() 
{
  Serial.begin(57600);
  while (!Serial) {}
  mySerial.begin(57600);
}

void loop() 
{
  if (mySerial.available() > 0 && mySerial.read()== 36) // $
  {
    if (mySerial.available() > 0 && mySerial.read()== 71)  // G
    {
      if (mySerial.available() > 0 && mySerial.read()== 78)  // N
      {
        if (mySerial.available() > 0 && mySerial.read()== 82)  // R
        {
          if ( mySerial.available() > 0 && mySerial.read()== 77)  // M
          {
            if (mySerial.available() > 0 && mySerial.read()== 67)  // C
            {
              while(mySerial.available() && i < 7) // подсчет запятых
              {
                if (mySerial.read() == 44)
                {
                  i++;
                }
              }
              if (mySerial.available() > 0)
              {
                s = mySerial.read();
                if (s != 46)
                {
                  Serial.println(s -'0');
                }
              }
              i = 0;
              Serial.println("НОВЫЙ ЦИКЛ");
            }
          }
        }
      }
    }
  }
}            

Эти карявые строки кода выкавыривают из пакета целочисленное значение скорости в милях т.е. цыфру перед запятой.

Работает даже на SoftwareSerial.h и на скорости 57600 бод.

Вопрос в чем: пока цыфра одна все нормально, а когда будет больше?! как мне цыфры по отдельности представить в чило? или можно как то число сразу достать до точки которое будет? 

Short Circuit
Short Circuit аватар
Offline
Зарегистрирован: 17.05.2015

вы решили все сварганить используя один только if (mySerial.available() ??

вы батенька мозахист...

svi
Offline
Зарегистрирован: 19.10.2017

Но вроде работает, а что не так? Я только так пока придумал.

5N62V
Offline
Зарегистрирован: 25.02.2016

svi пишет:

Вопрос в чем: пока цыфра одна все нормально, а когда будет больше?! как мне цыфры по отдельности представить в чило? или можно как то число сразу достать до точки которое будет? 

Я в шоке, что ЭТО может работать.

чтоб вычитать число , проще всего считать его в строку, а потом преобразовать с помощью функций atoi(), atof().  Хотя можно и в рукопашную: считываете цифры, пока не встретится точка, попутно помещая их в буфер. Определяете количество цифр, множите их на соответствующий порядок и складываете. Но, я так понимаю, Вы придумаете что-нить еще более экстравагантное. :))

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

svi пишет:

Вопрос в чем: пока цыфра одна все нормально, а когда будет больше?!

Да, вопрос именно в этом. Собственно, я Вам об этом уже писал в п. 3 сообщения №16.

sadman41
Онлайн
Зарегистрирован: 19.10.2016

5N62V пишет:

Хотя можно и в рукопашную: считываете цифры, пока не встретится точка, попутно помещая их в буфер. Определяете количество цифр, множите их на соответствующий порядок и складываете.

Можно и не множить, а прямо буфер затерминировать ('\0') и скормить atoi/atof-у

5N62V
Offline
Зарегистрирован: 25.02.2016

sadman41 пишет:

Можно и не множить, а прямо буфер затерминировать ('\0') и скормить atoi/atof-у

Понял, логично, премного благодарен! 

5N62V
Offline
Зарегистрирован: 25.02.2016

Я бы написал как -то так:

#include <SoftwareSerial.h>

SoftwareSerial hz(2,4);//но я не рекомендую юзать SoftwareSerial

float speed = 0;
byte satellits = 0;

void setup() {
  // чего-то тут пишем
}

void loop() {
if (hz.available() && hz.read()=='$')checkSentance();//еси встретили признак начала предложения

{
//выводим куда надо speed и satellits
}

}

void checkSentance(){//проверяем какое предложение пришло
  char buffer[5];// в идеале считываем название предложения в буфер
                 // но это в идеале
  for(byte i = 0; i<4; i++){
    readByte();              // просто считываем байт, и так  4 раза    
  }
 
  char x = readByte();
  if(x=='C')//значит пришла строка $GPRMC
  // отключите лишние строки в настройке модуля
  // не применяйте Глонасс, если Вы себе не злой Буратино
  speed = parseSentence(7);//значение после седьмой запятой
  if(x=='V')//значит пришла строка $$GPGSV
  satellits = parseSentence(3);//значение после третьей запятой
}

float parseSentence(byte n){//функция парсинга
  float result = 0;
  byte counter = 0;//счетчик запятых
  while (counter<n){//пока не досчитали до нужной запятой
    if(readByte() == ',') counter++;//просто считываем байты
    //если встретилась запятая - инкреминируем счетчик
  }
  char buffer[10];//объявляем буфер, куда будем считывать число
  counter = 0;// ну че я буду для индексирования новую переменную объявлять?!
  while(1){
    buffer[counter] = readByte();//считываем число в буфер познаково
    if(buffer[counter]==','){//пока не наткнемся на следующую запятую
      buffer[counter] = '\0';//терминалим буфер ( привет sadman41 ! )
      result = atof(buffer);//переводим считанный буфер в float
      return result;// возвращаем число
    }
    counter++;
  }
  
}

char readByte(){
  while(!hz.available());//ждем пока байт не появится во входном буфере UART
  return hz.read();// считываем байт
}

Ни разу не претендую на правильность, но должно работать. Хотя я не проверял.  Наверняка народ поправит, и подскажет как сделат лучше. :)

Прелесть данного подхода в том, что теперь ничего не стоит вычитать любое значение из любого предложения (из числа принимаемых, ессно), и никакие дурацкие библиотеки типа TinyGPS, которые ко всему еще и работают только на бодрейте 9600, не нужны.

svi
Offline
Зарегистрирован: 19.10.2017

5N62V пишет:

Я бы написал как -то так:

#include <SoftwareSerial.h>

SoftwareSerial hz(2,4);//но я не рекомендую юзать SoftwareSerial

float speed = 0;
byte satellits = 0;

void setup() {
  // чего-то тут пишем
}

void loop() {
if (hz.available() && hz.read()=='$')checkSentance();//еси встретили признак начала предложения

{
//выводим куда надо speed и satellits
}

}

void checkSentance(){//проверяем какое предложение пришло
  char buffer[5];// в идеале считываем название предложения в буфер
                 // но это в идеале
  for(byte i = 0; i<4; i++){
    readByte();              // просто считываем байт, и так  4 раза    
  }
 
  char x = readByte();
  if(x=='C')//значит пришла строка $GPRMC
  // отключите лишние строки в настройке модуля
  // не применяйте Глонасс, если Вы себе не злой Буратино
  speed = parseSentence(7);//значение после седьмой запятой
  if(x=='V')//значит пришла строка $$GPGSV
  satellits = parseSentence(3);//значение после третьей запятой
}

float parseSentence(byte n){//функция парсинга
  float result = 0;
  byte counter = 0;//счетчик запятых
  while (counter<n){//пока не досчитали до нужной запятой
    if(readByte() == ',') counter++;//просто считываем байты
    //если встретилась запятая - инкреминируем счетчик
  }
  char buffer[10];//объявляем буфер, куда будем считывать число
  counter = 0;// ну че я буду для индексирования новую переменную объявлять?!
  while(1){
    buffer[counter] = readByte();//считываем число в буфер познаково
    if(buffer[counter]==','){//пока не наткнемся на следующую запятую
      buffer[counter] = '\0';//терминалим буфер ( привет sadman41 ! )
      result = atof(buffer);//переводим считанный буфер в float
      return result;// возвращаем число
    }
    counter++;
  }
  
}

char readByte(){
  while(!hz.available());//ждем пока байт не появится во входном буфере UART
  return hz.read();// считываем байт
}

Ни разу не претендую на правильность, но должно работать. Хотя я не проверял.  Наверняка народ поправит, и подскажет как сделат лучше. :)

Прелесть данного подхода в том, что теперь ничего не стоит вычитать любое значение из любого предложения (из числа принимаемых, ессно), и никакие дурацкие библиотеки типа TinyGPS, которые ко всему еще и работают только на бодрейте 9600, не нужны.

 

Спасибо добрый человек!) Разобрался в вашем коде, до такого количества функций мне еще долеко :) Есть только пару моментов непонятных мне, не подскажете литературу какую можно почитать для освоения программной части Ардуино?

Код рабочий, вот только количество спутников я так понял нужно брать из другой строки  $GPGGA (там отображается количество активных (используемых) спутников, а не просто их видимое количество). Это я сам переделаю (благо код гибкий благодоря обилию функций), потом выложу.

И еще я понял что потерял месяц своей жизни в ожидании нового модуля)))) оказывается GPS NEO-6M все же может работать на частоте 5Гц, это первый что то глючной попался :D Опять настроил через U-center частоту 5Гц и скорость 57600 бод, и все :) 

5N62V
Offline
Зарегистрирован: 25.02.2016

svi пишет:

Спасибо добрый человек!) Разобрался в вашем коде, до такого количества функций мне еще долеко :) Есть только пару моментов непонятных мне, не подскажете литературу какую можно почитать для освоения программной части Ардуино?

Да на здоровье! :) Если непонятки по коду - спрашивайте. А по книгам вот прямо на этом сайте в поисковике вбивайте "книги по программированию", и получите кучу вариантов.

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

Тоже делаю аналогичное устройство, хочу применить метод описанный тут выше, но почему то не получается.Модуль gps neo6m перевел на скорость 57600, скорость Serial 57600, RX И TX модуля подключены к пинам 3 и 4 ардуины. Пробовал код представленный чуть выше, пару секунд принимает правильную информацию( скорость и кол-во спутников), а потом сплошные ошибки(кол-во спутников например 340). Вот мой код.

// настроить модуль GPS на скорость 57600 в программе UBLOX
//отключить все сообщения, кроме $GPRMC  и $GPGGA
#include <SoftwareSerial.h>

SoftwareSerial mySerial(4,3);//RX,TX,но я не рекомендую юзать SoftwareSerial

float speed = 0;
byte satellits = 0;

void setup() {
 Serial.begin(57600);
  while (!Serial) {}
  mySerial.begin(57600);
}

void loop() {
if (mySerial.available() && mySerial.read()=='$')checkSentance();//еси встретили признак начала предложения

{
//выводим куда надо speed и satellits
}

}

void checkSentance(){//проверяем какое предложение пришло
  char buffer[5];// в идеале считываем название предложения в буфер
                 // но это в идеале
  for(byte i = 0; i<4; i++){
    readByte();              // просто считываем байт, и так  4 раза    
  }
 
  char x = readByte();
  if(x=='C')//значит пришла строка $GPRMC
  // отключите лишние строки в настройке модуля
  // не применяйте Глонасс, если Вы себе не злой Буратино
  speed = parseSentence(7);//значение после седьмой запятой
  if(x=='A')//значит пришла строка $$GPGGA
  satellits = parseSentence(7);//значение после седьмой запятой
}

float parseSentence(byte n){//функция парсинга
  float result = 0;
  byte counter = 0;//счетчик запятых
  while (counter<n){//пока не досчитали до нужной запятой
    if(readByte() == ',') counter++;//просто считываем байты
    //если встретилась запятая - инкреминируем счетчик
  }
  char buffer[10];//объявляем буфер, куда будем считывать число
  counter = 0;// ну че я буду для индексирования новую переменную объявлять?!
  while(1){
    buffer[counter] = readByte();//считываем число в буфер познаково
    if(buffer[counter]==','){//пока не наткнемся на следующую запятую
      buffer[counter] = '\0';//терминалим буфер ( привет sadman41 ! )
      result = atof(buffer);//переводим считанный буфер в float
      return result;// возвращаем число
    }
    counter++;
  }
  
}

char readByte(){
  while(!mySerial.available());//ждем пока байт не появится во входном буфере UART
  return mySerial.read();// считываем байт
}

Подскажите что можно предпринять), а то библиотека TinyGPS медленно работает, все таки скорость в автомобиле быстро изменяется.

psych
Offline
Зарегистрирован: 14.08.2019

Доброго времени суток.

Чтобы темы не плодить однообразные, задам свой вопрос здесь. Надеюсь тема живет еще.
Столкнулся с похожей проблемой ардуины и нео6м.
в u-center подключаю модуль - работает
в ардуине читаю сырые данные - читаются
пробую библиотеки TinyGPS( ++) - ничего не работает.

Что делал до этого. долго пытался что-то рабочее написать на TinyGPS без +-ов. ничего не получалось. почитал что с +-ами библиотека лучше.  попробовал даже что-то получилось сделать запустил пример deviceexample чуть отредактирвоал под свои нужды и модуль. Вроде заработало. выдало координаты и время. я воодушевленный продолжил сборку своего устройства и когда собрал все вместе с остальной обвязкой, оказалось что ничего не работает.
Думал накосячил в коде или сборке. Перепроверил, перетестил. результата нет. Опять все разобрал до нуля подключаю модуль к ардуине и deviceexample больше не работает.
повторяю после всего этого
в u-center подключаю модуль - работает
в ардуине читаю сырые данные - читаются
пробую библиотеки TinyGPS( ++) - ничего не работает.

Помогите пожалуйста разобраться!

b707
Онлайн
Зарегистрирован: 26.05.2017

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

Или посмотрите что там внутри TinyGPS - скорее всего какая-нить запятая не соответвует выходному формату ваших данных, вот и не работает

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

было неоднократно на форуме, поищите Парсинг GPS

http://arduino.ru/forum/programmirovanie/parsing-nmea

 

psych
Offline
Зарегистрирован: 14.08.2019

b707 пишет:

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

Или посмотрите что там внутри TinyGPS - скорее всего какая-нить запятая не соответвует выходному формату ваших данных, вот и не работает

Да были уже подобные мысли. Подозреваю что проблема в настройках модуля, но каким бы мануалом я не пользовался перенастроить вывод данных модулем не получается. Гугл перерыт неоднократно. Подозреваю проблема в том что мои модули все пишут на вывод текстовое поле $GPTXT,01,01,01,ANTENNA OK*35. Так ли это?

буду благодарен если кто поделиться опытом по этому вопросу, то есть как настроить эти модули. GY-GPS6Mv2.

В мыслях сейчас найти причину и проапгредйть TinyGPS++ уж очень она мне понравилась. Не знаю почеу некоторые на нее ругаются. может из-за того что еще несовершенна.

b707
Онлайн
Зарегистрирован: 26.05.2017

psych пишет:

буду благодарен если кто поделиться опытом по этому вопросу, то есть как настроить эти модули. GY-GPS6Mv2.

 

зачем их вообще настраивать? Загляните в библиотеку, посмотрите, какие текстовые поля она парсит - и сравните с теми, что выдает модуль. Там делов-то на полчаса. Но только чтобы это сделать - нужно иметь ваш модуль на руках, так что вряд ли чей-то опыт будет вам полезен, придется самому.

psych
Offline
Зарегистрирован: 14.08.2019

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

 

psych
Offline
Зарегистрирован: 14.08.2019

b707 пишет:

psych пишет:

буду благодарен если кто поделиться опытом по этому вопросу, то есть как настроить эти модули. GY-GPS6Mv2.

 

зачем их вообще настраивать? Загляните в библиотеку, посмотрите, какие текстовые поля она парсит - и сравните с теми, что выдает модуль. Там делов-то на полчаса. Но только чтобы это сделать - нужно иметь ваш модуль на руках, так что вряд ли чей-то опыт будет вам полезен, придется самому.

Уже смотрел, но честно опыта пока маловато. Код вроде и понятен, но я так и не понял причины, если бы понял не задавал бы таких глупых вопросов.

 

5N62V
Offline
Зарегистрирован: 25.02.2016

psych пишет:

 Подозреваю проблема в том что мои модули все пишут на вывод текстовое поле $GPTXT,01,01,01,ANTENNA OK*35. Так ли это?

буду благодарен если кто поделиться опытом по этому вопросу, то есть как настроить эти модули. GY-GPS6Mv2.

Подключите модуль к U-centre и поодключайте все ненужные предложения. В 95 процентах случаев достаточно только rmc и gga. По дефолту там куча ненужного. Хотя конечно о Ваших нуждах можно только догадываться.

 

ЗЫ. TinyGPS++ - это еще тот шлак.

ЗЗЫ. Проверьте, сохраняются ли у Вас настройки модуля после его перезагрузки. Например, поменяли бодрейт, отключите модуль, потом подключите опять, и гляньте на каком бодрейте он подхватился У-центром. У меня попадалась парочка бракованных, ничего в ЕЕПРОМке не сохранялось. Их конфигурировать приходилось командами по уарт при  каждой инициализации.

psych
Offline
Зарегистрирован: 14.08.2019

в том и проблема что я не могу разобраться с настройками, то есть битрейт меняетс, но сохраняется только свойство в программе, при последующем подключении, но в настройках программы он как был так и остается, с отсльными аналогичная ситуация, в конфиге видно что свойство изменено, но пофакту ничего подобного. Как прошить я так и не разобрался. уже и файлы для квадрика пытался туда впихнуть, никакого эффекта или изменения так и не добился. Этот вопрос также интересует, поскольку данное кунг-фу тоже лишним не будет. А из требуемых задач у меня только получение координат по сути, в будущем конечно будет еще запросы к данному модулю, ибо меня удивила его способность приема в помещении. Этот вопрос мне также актуален, но боюсь он не относиться к теме, а создавать отдельную не хотелось бы. может я скину один из свох контактов для связи и вы расскажете что и как?

На счет шлака не знаю, поскольку заложенные вычисления в библиотеке мне как раз и нужны, конечно они у меня есть и отдельно от библиотеки, но раз есть в ней, то я могу съэкономить около20% памяти МК, почти если буду использовать эти функции. не прибегая к своим.

 

psych
Offline
Зарегистрирован: 14.08.2019

5N62V пишет:

У меня попадалась парочка бракованных, ничего в ЕЕПРОМке не сохранялось. Их конфигурировать приходилось командами по уарт при  каждой инициализации.

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

APJ
Offline
Зарегистрирован: 25.03.2015

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

 ss.print("$PUBX,41,1,3,3,38400,0*24\r\n");       // установить скорость 38400

// ss.print("$PUBX,41,1,0003,0001,19200,0*23\r\n"); //19200

ss.print("$PUBX,41,1,0003,0001,57600,0*2D\r\n"); // 57600

Команды выключения ненужных строк

//ss.print("$PUBX,40,GLL,0,1,0,0,0,0*5D
ss.println("$PUBX,40,GSV,0,0,0,0,0,0*59");
ss.println("$PUBX,40,GSA,0,0,0,0,0,0*4E");
ss.println("$PUBX,40,VTG,0,0,0,0,0,0*5E");
ss.println("$PUBX,40,ZDA,0,0,0,0,0,0*44");
ss.println("$PUBX,40,GLL,0,0,0,0,0,0*5C");

Может кому-нибудь пригодится.

psych
Offline
Зарегистрирован: 14.08.2019

к вопросу о том какие модули конкретно.

http://prntscr.com/osqunp

http://prntscr.com/osquy4

по снимкам думаю наличие eeprom видно, другой вопрос не является ли это бутафорией ))

 

5N62V
Offline
Зарегистрирован: 25.02.2016

APJ пишет:

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

 ss.print("$PUBX,41,1,3,3,38400,0*24\r\n");       // установить скорость 38400

// ss.print("$PUBX,41,1,0003,0001,19200,0*23\r\n"); //19200

ss.print("$PUBX,41,1,0003,0001,57600,0*2D\r\n"); // 57600

Команды выключения ненужных строк

//ss.print("$PUBX,40,GLL,0,1,0,0,0,0*5D
ss.println("$PUBX,40,GSV,0,0,0,0,0,0*59");
ss.println("$PUBX,40,GSA,0,0,0,0,0,0*4E");
ss.println("$PUBX,40,VTG,0,0,0,0,0,0*5E");
ss.println("$PUBX,40,ZDA,0,0,0,0,0,0*44");
ss.println("$PUBX,40,GLL,0,0,0,0,0,0*5C");

Может кому-нибудь пригодится.

О, прикольненько, искал недавно эту инфу, но че-та быстро не получилось найти, а как залез в мануал команд модуля, так и забил на это дело уже через 5 минут. Пошел путем простым: подключил еще один УАРТ-ЮСБ переходник параллельно модулю, и считывал конфигурационную пачку , которую U-centre слал в модуль.

psych
Offline
Зарегистрирован: 14.08.2019

APJ пишет:

Команды выключения ненужных строк

//ss.print("$PUBX,40,GLL,0,1,0,0,0,0*5D
ss.println("$PUBX,40,GSV,0,0,0,0,0,0*59");
ss.println("$PUBX,40,GSA,0,0,0,0,0,0*4E");
ss.println("$PUBX,40,VTG,0,0,0,0,0,0*5E");
ss.println("$PUBX,40,ZDA,0,0,0,0,0,0*44");
ss.println("$PUBX,40,GLL,0,0,0,0,0,0*5C");

Может кому-нибудь пригодится.

попробовал отключить одну строку и поменять скорость
 появляется такая строка, подозреваю ответ от модуля
⸮b⸮⸮L⸮M5:E⸮C⸮Aъ⸮⸮b⸮b⸮⸮R⸮
и все никакого результата
 строка на месте скорость та же.

APJ
Offline
Зарегистрирован: 25.03.2015

У меня на 8м всё работало. Возможно для 6м другие команды, но маловероятно.

psych
Offline
Зарегистрирован: 14.08.2019

Дорогие друзья, благодарю всех за помощь и новые знания, и советы. Однако проблема была совсем в другом.
Прежде всего проблема была. как и многие другие возникающие у меня по недоспотру. Дело в том что данные поступающие на парсинг были не совсем корректные, вместо повсеместно положенных GPRMC синтенции были указаны как GNRMC. Банально достаточно настроить GPS+Glonass на просто GPS и все.

Судя по всему я как-то по недосмтру прошил обе модели модулей неправильной прошивкой или сбросил на дефолт, отсюда и пошли эти проблемы. Сейчас проверю сохраняемость настроек при отключении питания.

psych
Offline
Зарегистрирован: 14.08.2019

проверено, настройки сохраняется.

psych
Offline
Зарегистрирован: 14.08.2019

Предыдущее сообщение я поторопился написать, утром настройки слетели. И продолжают слетать.

Решил проблему следующим образом:
модифицировал библиотеку добавив между строками 30 и 31

#define _GNRMCterm   "GNRMC"

также добавил условие на строке 211

if (!strcmp(term, _GPRMCterm) || !strcmp(term, _GNRMCterm))
      curSentenceType = GPS_SENTENCE_GPRMC;
    else if (!strcmp(term, _GPGGAterm))
      curSentenceType = GPS_SENTENCE_GPGGA;
    else
      curSentenceType = GPS_SENTENCE_OTHER;

 

Gabandis
Offline
Зарегистрирован: 12.02.2020

Доброго времени суток!         

Тем же озадачился, произошла беда с кпп в авто, привод спидометра работать не будет пока кпп не заменю:(

Вспомнил что валяется без дела голый чип atmega 328p и neo 6m (собирался собирать квадрокоптер, в итоге купил готовый:))

Слепил код из частей найденых в просторах интернета, прошу ткнуть носом в ошибки

1)когда стою на месте генерит 1гц  а не нужно генерить ничего:)

2)наверное правельнее взять км/ч перевести в м/с потом умножать на 6(датчик скорости выдает 6имп. за 1м пройденего пути) если сразу брать м/с пара знаков после запятой теряется и после умножения может приверать....

3)как бы вы сделали?

а так вроде работает...

#include <nmea.h>
NMEA gps(GPRMC);

void setup() {
Serial.begin(9600);
pinMode (9,OUTPUT); // выход генератора
TCCR1A=0;TCCR1B=0;
}
void loop() {
static uint32_t reqfreq=0; //переменная запроса частоты
uint32_t ocr=OCR1A;  uint16_t divider=1;  float freq; 
  if (Serial.available() > 0 ) {
    char c = Serial.read();
    if (gps.decode(c)) {
      if (gps.gprmc_status() == 'A') {
       if (gps.gprmc_speed(MPS) > 0){ reqfreq = gps.gprmc_speed(MPS)*6; 
if (reqfreq==0 || reqfreq>F_CPU/2) {return;}
 ocr = (F_CPU / reqfreq /2 /divider); 
  byte shifts[] = {3,3,2,2};
   for(byte i = 0; i < 4; i++){
     if (ocr > 65536) { divider <<= shifts[i];
       ocr = F_CPU / reqfreq /2 /divider; }
      else { TCCR1B = (i+1)|(1<<WGM12);  break; }  }
     OCR1A=ocr-1; TCCR1A=1<<COM1A0;
    freq= (float) F_CPU/2 / (OCR1A+1) /divider;
 }
} 
}
}
}

Gabandis
Offline
Зарегистрирован: 12.02.2020

В общем переделал на вот так:

#include <nmea.h>
NMEA gps(GPRMC);

void setup() {
Serial.begin(9600);
pinMode (9,OUTPUT); // выход генератора
TCCR1A=0;TCCR1B=0;
}
void loop() {
static uint32_t reqfreq=0; //переменная запроса частоты
uint32_t ocr=OCR1A;  uint16_t divider=1;  float freq; 
  if (Serial.available() > 0 ) {
    char c = Serial.read();
    if (gps.decode(c)) {
      if (gps.gprmc_status() == 'A') {
       if (gps.gprmc_speed(KMPH) > 0){ reqfreq = gps.gprmc_speed(KMPH)*6004/3600; 
if (reqfreq==0 || reqfreq>F_CPU/2) {return;}
 ocr = (F_CPU / reqfreq /2 /divider); 
  byte shifts[] = {3,3,2,2};
   for(byte i = 0; i < 4; i++){
     if (ocr > 65536) { divider <<= shifts[i];
       ocr = F_CPU / reqfreq /2 /divider; }
      else { TCCR1B = (i+1)|(1<<WGM12);  break; }  }
     OCR1A=ocr-1; TCCR1A=1<<COM1A0;
    freq= (float) F_CPU/2 / (OCR1A+1) /divider;
 }
} 
}
}
}