sâmbătă, 28 iunie 2014

Receptor GPS conectat la un Arduino (3)

   Pana acum am folosit librariile TinyGPS si TinyGPS++ create de Mikal Hart, dar receptorul folosit de mine, nu transmite datele in format GPGCA si GPRMC, ci in format GPGCA si GPVTG si de aceea nu puteam primi informatia despre viteza...
   Am realizat asta abia dupa ce am recitit articolul  tronixstuff: Arduino and EM406A GPS si am retestat primul sketch, fara librarii, cand am obtinut pe ecranul de monitorizare seriala:
   Dupa ce am mai studiat articolul NMEA data, am gasit ca viteza in km/h este in campul $GPVGT, la pozitia a 7-a:
si am reusit sa o "scot" cu ajutorul librariei TinyGPS++, deoarece autorul lor, Mikal Hart, s-a gandit ca mai sunt si alte date si sisteme de codare date, asa ca a creat o comanda speciala de extragere a unei valori dintr-un camp anume, cum este:
TinyGPSCustom magneticVariation(gps, "GPRMC", 10)
care se combina cu cea de afisare:
if (magneticVariation.isUpdated())
{
  Serial.print("Magnetic variation is ");
  Serial.println(magneticVariation.value());
}
   Deoarece eu aveam nevoie de viteza, am folosit urmatoarea parte de extragere a vitezei
   // for speed in kilometers per hour
   TinyGPSCustom zdop(gps, "GPVTG", 7); // $GPVTG sentence, 7th element 
iar partea de afisare:
   // viteza extrasa custom
   lcd.setCursor(0,3); // put cursor at colon x and row y
   lcd.print("viteza: ");
   int viteza = atoi (zdop.value());
   // lcd.print(zdop.value());
   if (viteza>100.0) lcd.print(viteza);
   else
   if (viteza>10.0) {lcd.print(" "); lcd.print(viteza);}
   else 
   if (viteza<10.0) {lcd.print("  "); lcd.print(viteza);}
   lcd.print("km/h");

   Montajul de test, in timp ce masina se deplasa (in stanga este viteza obtinuta cum am aratat mai sus, iar in dreapta e ce ar afisa libraria, adica zero permanent):
 
   Ulterior, am mai modificat sketch-ul si am facut si 2 filmulete:
- receptor GPS si Arduino (3)
receptor GPS si Arduino (4)
   Sketch-ul folosit este:
// source: http://arduiniana.org/libraries/tinygpsplus/
// for see your position: http://www.gps-coordinates.net/
// for new article made by niq_rohttp://nicuflorica.blogspot.com/

#include <TinyGPS++.h>
#include <SoftwareSerial.h>
/*
   This sample code demonstrates the normal use of a TinyGPS++ (TinyGPSPlus) object.
   It requires the use of SoftwareSerial, and assumes that you have a
   4800-baud serial GPS device hooked up on pins 4(rx) and 3(tx).
*/
static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 4800;

// The TinyGPS++ object
TinyGPSPlus gps;

// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);

#include <LiquidCrystal.h>
// folosesc libraria pentru afisaje LCD simple
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
// indic modul de legare, vezi mai jos:
/*                                    -------------------
                                      |  LCD  | Arduino |
                                      -------------------
 LCD RS pin to digital pin 7          |  RS   |   D7    |
 LCD Enable pin to digital pin 6      |  E    |   D8    |
 LCD D4 pin to digital pin 5          |  D4   |   D9    |
 LCD D5 pin to digital pin 4          |  D5   |   D10   |
 LCD D6 pin to digital pin 3          |  D6   |   D11   |
 LCD D7 pin to digital pin 2          |  D7   |   D12   |
 LCD R/W pin to ground                |  R/W  |   GND   |
                                      -------------------
niq_ro adapted this sketch for see data on 2004 LCD
*/

// for speed in knots (noduri) 
//TinyGPSCustom sdop(gps, "GPVTG", 5); // $GPVTG sentence, 5th element
// for speed in kilometers per hour
TinyGPSCustom zdop(gps, "GPVTG", 7); // $GPVTG sentence, 7th element 

void setup()
{
  Serial.begin(115200);
  ss.begin(GPSBaud);

  Serial.println(F("FullExample.ino"));
  Serial.println(F("An extensive example of many interesting TinyGPS++ features"));
  Serial.print(F("Testing TinyGPS++ library v. ")); Serial.println(TinyGPSPlus::libraryVersion());
  Serial.println(F("by Mikal Hart"));
  Serial.println();
  Serial.println(F("Sats HDOP Latitude   Longitude   Fix  Date       Time     Date Alt    Course Speed Card  Distance Course Card  Chars Sentences Checksum"));
  Serial.println(F("          (deg)      (deg)       Age                      Age  (m)    --- from GPS ----  ---- to London  ----  RX    RX        Fail"));
  Serial.println(F("---------------------------------------------------------------------------------------------------------------------------------------"));


lcd.begin(20, 4); // set up the LCD's number of columns and rows: 

 lcd.clear(); // clear the screen
 lcd.setCursor(1, 0); // put cursor at colon x and row y
 lcd.print("GPS data - 6.2014"); // print a text
 lcd.setCursor(1, 1); // put cursor at colon x and row y
 lcd.print("ver 1.5 by niq_ro"); // print a text
 lcd.setCursor(1, 2); // put cursor at colon x and row y
 lcd.print("Craiova - Romania"); // print a text
 delay (2000);
 lcd.clear(); // clear the screen
}

void loop()
{
  // partea de ecran LCD 20x4
  afisareecran();
  
  static const double LONDON_LAT = 51.508131, LONDON_LON = -0.128002;

  printInt(gps.satellites.value(), gps.satellites.isValid(), 5);
  printInt(gps.hdop.value(), gps.hdop.isValid(), 5);
  printFloat(gps.location.lat(), gps.location.isValid(), 11, 6);
  printFloat(gps.location.lng(), gps.location.isValid(), 12, 6);
  printInt(gps.location.age(), gps.location.isValid(), 5);
  printDateTime(gps.date, gps.time);
  printFloat(gps.altitude.meters(), gps.altitude.isValid(), 7, 2);
  printFloat(gps.course.deg(), gps.course.isValid(), 7, 2);
  printFloat(gps.speed.kmph(), gps.speed.isValid(), 6, 2);
  printStr(gps.course.isValid() ? TinyGPSPlus::cardinal(gps.course.value()) : "*** ", 6);

  unsigned long distanceKmToLondon =
    (unsigned long)TinyGPSPlus::distanceBetween(
      gps.location.lat(),
      gps.location.lng(),
      LONDON_LAT, 
      LONDON_LON) / 1000;
  printInt(distanceKmToLondon, gps.location.isValid(), 9);

  double courseToLondon =
    TinyGPSPlus::courseTo(
      gps.location.lat(),
      gps.location.lng(),
      LONDON_LAT, 
      LONDON_LON);

  printFloat(courseToLondon, gps.location.isValid(), 7, 2);

  const char *cardinalToLondon = TinyGPSPlus::cardinal(courseToLondon);

  printStr(gps.location.isValid() ? cardinalToLondon : "*** ", 6);

  printInt(gps.charsProcessed(), true, 6);
  printInt(gps.sentencesWithFix(), true, 10);
  printInt(gps.failedChecksum(), true, 9);

  // speed in km/h
  Serial.print(" ");
  Serial.print(zdop.value());
  int vitesa1 = atoi (zdop.value());
  Serial.print("/");
  Serial.print(vitesa1);
  Serial.println();
  
  smartDelay(1000);

  if (millis() > 5000 && gps.charsProcessed() < 10)
    Serial.println(F("No GPS data received: check wiring"));
}

// This custom version of delay() ensures that the gps object
// is being "fed".
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);
}

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);
}

static void printDateTime(TinyGPSDate &d, TinyGPSTime &t)
{
  if (!d.isValid())
  {
    Serial.print(F("********** "));
  }
  else
  {

    char sz[32];
   sprintf(sz, "%02d/%02d/%02d ", d.month(), d.day(), d.year());
//    sprintf(sz, "%02d/%02d/%02d ", gps.date.month(), gps.date.day(), gps.date.year());
    Serial.print(sz);
  }
  
  if (!t.isValid())
  {
    Serial.print(F("******** "));
  }
  else
  {
    char sz[32];
    sprintf(sz, "%02d:%02d:%02d ", t.hour(), t.minute(), t.second());
//  sprintf(sz, "%02d:%02d:%02d ", gps.time.hour(), gps.time.minute(), gps.time.second());
    Serial.print(sz);

  }

  printInt(d.age(), d.isValid(), 5);
  smartDelay(0);
}

static void printStr(const char *str, int len)
{
  int slen = strlen(str);
  for (int i=0; i<len; ++i)
    Serial.print(i<slen ? str[i] : ' ');
  smartDelay(0);
}

static void afisareecran()
{
// lcd.clear(); // clear the screen

// partea de ora
// ora de vara a Romaniei - 
// trebuie sa pun un comutator pentru selectie de iarna si de vara
 int ora = 3 + gps.time.hour();
 if (ora ==24) ora=0;
 if (ora ==25) ora=1;
 if (ora ==26) ora=2;
 lcd.setCursor(0,2); // put cursor at colon 2 and row 2
 if (ora<10) lcd.print(" "); 
 lcd.print(ora); 
 lcd.print(":");
 if (gps.time.minute()<10) lcd.print("0"); 
 lcd.print(gps.time.minute()); 
 lcd.print(":");
 if (gps.time.second()<10) lcd.print("0"); 
 lcd.print(gps.time.second()); 

// parte de coordonate GPS
 lcd.setCursor(0,0); // put cursor at colon 0 and row 0 = left/up
 lcd.print("LAT:");
 lcd.print(gps.location.lat(),6);
 lcd.write(0b11011111);
 lcd.setCursor(0,1); // put cursor at colon 0 and row 1 
 lcd.print("LON:");
 lcd.print(gps.location.lng(),6);
 lcd.write(0b11011111);

// numar sateliti receptionati
 lcd.setCursor(10,2); // put cursor at colon 15 and row 2
 lcd.print(gps.satellites.value());
 if (gps.satellites.value() == 1) lcd.print(" satelit ");
 else lcd.print(" sateliti");

// viteza
/*
lcd.setCursor(10,3); // put cursor at colon x and row y
double viteza = gps.speed.kmph(); 
// tests
// double viteza = 0.;
// double viteza = 5;
// double viteza = 14;
// double viteza = 104;
 if (viteza>100.0) lcd.print(viteza);
 else
 if (viteza>10.0) {lcd.print(" "); lcd.print(viteza);}
 else 
 if (viteza<10.0) {lcd.print("  "); lcd.print(viteza);}
// lcd.print(viteza);
// lcd.print(gps.speed.kmph());
 lcd.print("km/h");
*/

// altitudine
  lcd.setCursor(16,0); // put cursor at colon 16 and row 0
  lcd.print("ALT:");
  int cota = gps.altitude.meters();
  lcd.setCursor(15,1); // put cursor at colon 15 and row 1
// cota=5;
//cota=15;
//cota=497;
//cota=2056;
 if (cota>1000) lcd.print(cota);
 else
 if (cota>100) {lcd.print(" "); lcd.print(cota);}
 else
 if (cota>10) {lcd.print("  "); lcd.print(cota);}
 if (cota<10) {lcd.print("   "); lcd.print(cota);}
 lcd.print("m");
 
// viteza extrasa custom
 lcd.setCursor(0,3); // put cursor at colon x and row y
 lcd.print("viteza: ");
 int viteza = atoi (zdop.value());
// lcd.print(zdop.value());
 if (viteza>100.0) lcd.print(viteza);
 else
 if (viteza>10.0) {lcd.print(" "); lcd.print(viteza);}
 else 
 if (viteza<10.0) {lcd.print("  "); lcd.print(viteza);}
 lcd.print("km/h");
 }  
pentru schema de conectare din articolul anterior:

PS: intre timp am folosit caractere mari pentru viteza:
 
   Am facut si un filmulet numit receptor GPS si Arduino (5):

PS: Am reusit sa fac si niste teste in masina, doar ca am doar poze momentan:

14.7.2014
   In weak-end, am reusit sa mai fac teste pe masina:
inclusiv 3 filmulete:


miercuri, 25 iunie 2014

Receptor GPS conectat la un Arduino (2)

   Dupa ce am mai studiat articolul TinyGPS++: A *NEW* Full-featured GPS/NMEA Parser for Arduino, in care se explica comenzile librariei TinyGPS++, m-am oprit la urmatoarele:
Serial.println(gps.location.lat()); // Latitudine in grade (double)
Serial.println(gps.location.lng()); // Longitudine in grade (double)
Serial.println(gps.time.hour()); // Ore (0-23) (u8)
Serial.println(gps.time.minute()); // Minute (0-59) (u8)
Serial.println(gps.time.second()); // Seconde (0-59) (u8)
Serial.println(gps.speed.kmph()); // Viteza in kilometri pe ora (double)
Serial.println(gps.satellites.value()); // Numar de sateliti receptionati (u32)
deoarece vreau sa afisez aceste date pe un LCD2004, cel pe care l-am prezentat in articolul Afisajul alfanumeric cu 20 de coloane si 4 randuri (LCD2004) comandat de Arduino).
   Am facut urmatoarea schema de conexiuni:
   Deoarece consumul afisajului (mai ales a LED-ului de fundal) + receptorul GPS este prea mare, am alimentat tot montajul de la un alimentator extern cu 5V, apoi pentru a putea fi usor de testat am ales sa il alimentez dintr-ul incarcator de telefon mobil care scoate 5V/1A prin mufa USB de pe placa Arduino. Cand sa sa fac testele in masina, pentru partea cu viteza, o sa folosesc un invertor, care are si mufa pentru 5V/2A:
 
   Sketch-ul folosit, este cel pe care l-am folosit si in articolul precedent (Receptor GPS conectat la un Arduino) cu completarea partii de afisare pe LCD2004:
// source: http://arduiniana.org/libraries/tinygpsplus/
// for see your position: http://www.gps-coordinates.net/
// for new article made by niq_rohttp://nicuflorica.blogspot.com/

#include <TinyGPS++.h>
#include <SoftwareSerial.h>
/*
   This sample code demonstrates the normal use of a TinyGPS++ (TinyGPSPlus) object.
   It requires the use of SoftwareSerial, and assumes that you have a
   4800-baud serial GPS device hooked up on pins 4(rx) and 3(tx).
*/
static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 4800;

// The TinyGPS++ object
TinyGPSPlus gps;

// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);

#include <LiquidCrystal.h>
// folosesc libraria pentru afisaje LCD simple
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
// indic modul de legare, vezi mai jos:
/*                                    -------------------
                                      |  LCD  | Arduino |
                                      -------------------
 LCD RS pin to digital pin 7          |  RS   |   D7    |
 LCD Enable pin to digital pin 6      |  E    |   D8    |
 LCD D4 pin to digital pin 5          |  D4   |   D9    |
 LCD D5 pin to digital pin 4          |  D5   |   D10   |
 LCD D6 pin to digital pin 3          |  D6   |   D11   |
 LCD D7 pin to digital pin 2          |  D7   |   D12   |
 LCD R/W pin to ground                |  R/W  |   GND   |
                                      -------------------
niq_ro adapted this sketch for see data on 2004 LCD
*/

 

void setup()
{
  Serial.begin(115200);
  ss.begin(GPSBaud);

  Serial.println(F("FullExample.ino"));
  Serial.println(F("An extensive example of many interesting TinyGPS++ features"));
  Serial.print(F("Testing TinyGPS++ library v. ")); Serial.println(TinyGPSPlus::libraryVersion());
  Serial.println(F("by Mikal Hart"));
  Serial.println();
  Serial.println(F("Sats HDOP Latitude   Longitude   Fix  Date       Time     Date Alt    Course Speed Card  Distance Course Card  Chars Sentences Checksum"));
  Serial.println(F("          (deg)      (deg)       Age                      Age  (m)    --- from GPS ----  ---- to London  ----  RX    RX        Fail"));
  Serial.println(F("---------------------------------------------------------------------------------------------------------------------------------------"));


lcd.begin(20, 4); // set up the LCD's number of columns and rows: 

 lcd.clear(); // clear the screen
 lcd.setCursor(1, 0); // put cursor at colon 2 and row 0 = left/up
 lcd.print("GPS data"); // print a text
 lcd.setCursor(2, 1); // put cursor at colon 0 and row 0 = left/down
 lcd.print("ver 1.0 by niq_ro"); // print a text
 delay (2000);
 lcd.clear(); // clear the screen



}

void loop()
{
  // partea de ecran LCD 20x4
  afisareecran();
  
  static const double LONDON_LAT = 51.508131, LONDON_LON = -0.128002;

  printInt(gps.satellites.value(), gps.satellites.isValid(), 5);
  printInt(gps.hdop.value(), gps.hdop.isValid(), 5);
  printFloat(gps.location.lat(), gps.location.isValid(), 11, 6);
  printFloat(gps.location.lng(), gps.location.isValid(), 12, 6);
  printInt(gps.location.age(), gps.location.isValid(), 5);
  printDateTime(gps.date, gps.time);
  printFloat(gps.altitude.meters(), gps.altitude.isValid(), 7, 2);
  printFloat(gps.course.deg(), gps.course.isValid(), 7, 2);
  printFloat(gps.speed.kmph(), gps.speed.isValid(), 6, 2);
  printStr(gps.course.isValid() ? TinyGPSPlus::cardinal(gps.course.value()) : "*** ", 6);

  unsigned long distanceKmToLondon =
    (unsigned long)TinyGPSPlus::distanceBetween(
      gps.location.lat(),
      gps.location.lng(),
      LONDON_LAT, 
      LONDON_LON) / 1000;
  printInt(distanceKmToLondon, gps.location.isValid(), 9);

  double courseToLondon =
    TinyGPSPlus::courseTo(
      gps.location.lat(),
      gps.location.lng(),
      LONDON_LAT, 
      LONDON_LON);

  printFloat(courseToLondon, gps.location.isValid(), 7, 2);

  const char *cardinalToLondon = TinyGPSPlus::cardinal(courseToLondon);

  printStr(gps.location.isValid() ? cardinalToLondon : "*** ", 6);

  printInt(gps.charsProcessed(), true, 6);
  printInt(gps.sentencesWithFix(), true, 10);
  printInt(gps.failedChecksum(), true, 9);
  Serial.println();
  
  smartDelay(1000);

  if (millis() > 5000 && gps.charsProcessed() < 10)
    Serial.println(F("No GPS data received: check wiring"));
}

// This custom version of delay() ensures that the gps object
// is being "fed".
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);
}

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);
}

static void printDateTime(TinyGPSDate &d, TinyGPSTime &t)
{
  if (!d.isValid())
  {
    Serial.print(F("********** "));
  }
  else
  {

    char sz[32];
   sprintf(sz, "%02d/%02d/%02d ", d.month(), d.day(), d.year());
//    sprintf(sz, "%02d/%02d/%02d ", gps.date.month(), gps.date.day(), gps.date.year());
    Serial.print(sz);
  }
  
  if (!t.isValid())
  {
    Serial.print(F("******** "));
  }
  else
  {
    char sz[32];
    sprintf(sz, "%02d:%02d:%02d ", t.hour(), t.minute(), t.second());
//  sprintf(sz, "%02d:%02d:%02d ", gps.time.hour(), gps.time.minute(), gps.time.second());
    Serial.print(sz);

  }

  printInt(d.age(), d.isValid(), 5);
  smartDelay(0);
}

static void printStr(const char *str, int len)
{
  int slen = strlen(str);
  for (int i=0; i<len; ++i)
    Serial.print(i<slen ? str[i] : ' ');
  smartDelay(0);
}

static void afisareecran()
{
// lcd.clear(); // clear the screen

// partea de ora
// ora de vara a Romaniei - 
// trebuie sa pun un comutator pentru selectie de iarna si de vara
 int ora = 3 + gps.time.hour();
 if (ora ==24) ora=0;
 if (ora ==25) ora=1;
 if (ora ==26) ora=2;
 lcd.setCursor(0,2); // put cursor at colon 2 and row 2
 if (ora<10) lcd.print(" "); 
 lcd.print(ora); 
 lcd.print(":");
 if (gps.time.minute()<10) lcd.print("0"); 
 lcd.print(gps.time.minute()); 
 lcd.print(":");
 if (gps.time.second()<10) lcd.print("0"); 
 lcd.print(gps.time.second()); 

// parte de coordonate GPS
 lcd.setCursor(0,0); // put cursor at colon 0 and row 0 = left/up
 lcd.print("LAT: ");
 lcd.print(gps.location.lat(),6);
 lcd.write(0b11011111);
 lcd.setCursor(0,1); // put cursor at colon 0 and row 1 
 lcd.print("LON: ");
 lcd.print(gps.location.lng(),6);
 lcd.write(0b11011111);

// numar sateliti receptionati
 lcd.setCursor(15,2); // put cursor at colon 15 and row 2
 lcd.print(gps.satellites.value());
 lcd.print(" sat");

// viteza
 lcd.setCursor(6,3); // put cursor at colon 6 and row 3
 double viteza = gps.speed.kmph(); 
 if (viteza<10.0) lcd.print("  ");
 if (viteza<100.0) lcd.print(" ");
 lcd.print(viteza);
 lcd.print("km/h");
}  
   Am facut si un filmulet numit receptor GPS si Arduino (2)
26.06.2014
   Am mai aranjat la sketch, pentru a afisa si altitudinea:
apoi m-am gandit sa folosesc si libraria TinyGPS, cea dinaintea celei folosite pana acum (TinyGPS++), dupa informatiile din articolul tronixstuff: Arduino and EM406A GPS.
   Pentru a putea conectat la masina, am folosit elastice cu care am prin placa Arduino si afisajul de placa de test (breadboard):
   Am lasat afisarea acea ciudata la viteza de -1.00km/h pentru a vedea daca apare vreo modificare, cat de mica in mers...