I use TinyGPS++ library made by Mikal Hart and I extract speed:
TinyGPSCustom zdop(gps, "GPVTG", 7); // $GPVTG sentence, 7th elementI designed this schematic for tests:
// source: http://arduiniana.org/libraries/tinygpsplus/
// for see your position: http://www.gps-coordinates.net/
// for new article made by niq_ro: http://nicuflorica.blogspot.com/
// & http://arduiniq.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
*/
/* A set of custom made large numbers for a 16x2 LCD using the
LiquidCrystal library. Works with displays compatible with the
Hitachi HD44780 driver. Made by Michael Pilcher, 2/9/2010
*/
int x = 0;
// the 8 arrays that form each segment of the custom numbers
byte LT[8] =
{
B00111,
B01111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111
};
byte UB[8] =
{
B11111,
B11111,
B11111,
B00000,
B00000,
B00000,
B00000,
B00000
};
byte RT[8] =
{
B11100,
B11110,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111
};
byte LL[8] =
{
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B01111,
B00111
};
byte LB[8] =
{
B00000,
B00000,
B00000,
B00000,
B00000,
B11111,
B11111,
B11111
};
byte LR[8] =
{
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11110,
B11100
};
byte UMB[8] =
{
B11111,
B11111,
B11111,
B00000,
B00000,
B00000,
B11111,
B11111
};
byte LMB[8] =
{
B11111,
B00000,
B00000,
B00000,
B00000,
B11111,
B11111,
B11111
};
// 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:
// assignes each segment a write number
lcd.createChar(8,LT);
lcd.createChar(1,UB);
lcd.createChar(2,RT);
lcd.createChar(3,LL);
lcd.createChar(4,LB);
lcd.createChar(5,LR);
lcd.createChar(6,UMB);
lcd.createChar(7,LMB);
lcd.clear(); // clear the screen
lcd.setCursor(1, 0); // put cursor at colon x and row y
lcd.print("GPS data - 7.2014"); // print a text
lcd.setCursor(0, 1); // put cursor at colon x and row y
lcd.print("ver 1.6.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
lcd.setCursor(0, 3); // put cursor at colon x and row y
lcd.print("(TinyGPS++ library)"); // print a text
delay (2000);
lcd.clear(); // clear the screen
/*
// testare la inceput mod afisare viteza
lcd.setCursor(2,0);
lcd.print("niq_ro testeaza");
lcd.setCursor(1,1);
lcd.print("afisarea vitezei:");
for (int q=0; q<120; q=q++)
{
vitezamare(q);
lcd.setCursor(12,3);
lcd.print("km/h");
delay(200);
lcd.setCursor(0,2);
lcd.print(" ");
lcd.setCursor(0,3);
lcd.print(" ");
}
*/
lcd.clear(); // clear the screen
delay(500);
}
void loop()
{
// partea de ecran LCD 20x4
afisareecran();
// scot viteza
int viteza = atoi (zdop.value());
//int viteza = 123;
//int viteza = 456;
//int viteza = 789;
//int viteza = 92;
//int viteza = 6;
//int viteza = 0;
vitezamare(viteza);
lcd.setCursor(12,3);
lcd.print("km/h");
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(12,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(16,0); // put cursor at colon 15 and row 2
lcd.print(gps.satellites.value());
// if (gps.satellites.value() == 1) lcd.print(" satelit ");
// else
lcd.print("sat");
// 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");
*/
}
void custom0O() // uses segments to build the number 0
{
lcd.setCursor(x, 2);
lcd.write(8);
lcd.write(1);
lcd.write(2);
lcd.setCursor(x, 3);
lcd.write(3);
lcd.write(4);
lcd.write(5);
}
void custom1()
{
lcd.setCursor(x,2);
lcd.write(1);
lcd.write(2);
lcd.setCursor(x,3);
lcd.write(4);
lcd.write(255);
lcd.write(4);
}
void custom2()
{
lcd.setCursor(x,2);
lcd.write(6);
lcd.write(6);
lcd.write(2);
lcd.setCursor(x, 3);
lcd.write(3);
lcd.write(7);
lcd.write(7);
}
void custom3()
{
lcd.setCursor(x,2);
lcd.write(6);
lcd.write(6);
lcd.write(2);
lcd.setCursor(x, 3);
lcd.write(7);
lcd.write(7);
lcd.write(5);
}
void custom4()
{
lcd.setCursor(x,2);
lcd.write(3);
lcd.write(4);
lcd.write(2);
lcd.setCursor(x+2, 3);
lcd.write(255);
}
void custom5()
{
lcd.setCursor(x,2);
lcd.write(255);
lcd.write(6);
lcd.write(6);
lcd.setCursor(x, 3);
lcd.write(7);
lcd.write(7);
lcd.write(5);
}
void custom6()
{
lcd.setCursor(x,2);
lcd.write(8);
lcd.write(6);
lcd.write(6);
lcd.setCursor(x, 3);
lcd.write(3);
lcd.write(7);
lcd.write(5);
}
void custom7()
{
lcd.setCursor(x,2);
lcd.write(1);
lcd.write(1);
lcd.write(2);
lcd.setCursor(x+1, 3);
lcd.write(8);
}
void custom8()
{
lcd.setCursor(x,2);
lcd.write(8);
lcd.write(6);
lcd.write(2);
lcd.setCursor(x, 3);
lcd.write(3);
lcd.write(7);
lcd.write(5);
}
void custom9()
{
lcd.setCursor(x,2);
lcd.write(8);
lcd.write(6);
lcd.write(2);
lcd.setCursor(x, 3);
lcd.write(7);
lcd.write(7);
lcd.write(5);
}
// subrutina de afisare a numerelor
void afisarenumar(int numar)
{
switch (numar)
{
case 0:
custom0O();
break;
case 1:
custom1();
break;
case 2:
custom2();
break;
case 3:
custom3();
break;
case 4:
custom4();
break;
case 5:
custom5();
break;
case 6:
custom6();
break;
case 7:
custom7();
break;
case 8:
custom8();
break;
case 9:
custom9();
break;
}
}
void vitezamare(int viteza)
{
// sterg zona de afisare a vitezei
lcd.setCursor(0,2);
lcd.print(" ");
lcd.setCursor(0,3);
lcd.print(" ");
if (viteza>=100)
{
x = 0;
afisarenumar(int(viteza/100));
viteza=viteza % 100;
x = x + 4;
afisarenumar(viteza/10);
x = x + 4;
afisarenumar(viteza % 10);
}
else
if (viteza>=10)
{
lcd.setCursor(0,2);
lcd.print(" ");
lcd.setCursor(0,3);
lcd.print(" ");
x = 4;
afisarenumar(viteza/10);
x = x + 4;
afisarenumar(viteza % 10);
}
else
if (viteza<10)
{
lcd.setCursor(0,2);
lcd.print(" ");
lcd.setCursor(0,3);
lcd.print(" ");
x = 8;
afisarenumar(viteza);
}
}
I made few pics with speedometer in moving car:
Also, I made few movies:
Bibliography:
Why cant I get the "Satellites used" , the number showed on LCD always "0", even I use the "Customfield " function of "TinyGPS.
ReplyDeleteAny suggestion ? Thanks for your help !!
if GPS receiver is an older model, you need to have great patience.. sometimes 3-5 minutes
ReplyDeleteHi Nicu, great blog, nice place to learn some about Arduino, I did this project, work nice thanks so much José
ReplyDeleteyou can send me few pics?
DeleteHow accurate have you found the Arduino-based speedometer when compared to the car's own speedo? I know that cars are allowed to read slightly higher than the true speed without failing their MOT (though not lower), so I'm quite curious as to whether you find the home-made one to compare well against the car.
ReplyDeleteRaymond @ CKS Global Solutions LTD
Nice work, Nicu,
ReplyDeleteI appreciate this posting is quite old and understand that you may not respond to this enquiry.
Would you be kind enough to post your earlier code versions?
Alternatively, how difficult is it to invoke clock display, as shown in your videos.
I can see the relevant code (print date time) in ver.1.6.5 but obviously it is not enabled.
Same for the 'distance to London' snippet.
Thank you for your blog.
sorry, I losted older projects... you have GPS receiver like mine or newest ?
DeleteThank You for your reply, Nicu.
ReplyDeleteI am using a UBLOX NEO 6 running at 9600 baud.
Your sketch displays Lat/Log OK. It displays 'BIG Font' Speedometer digits (00), but has not been tested for speedometer functionality as project is still at prototype stage on bench.
Thanks once again for your time.
I do have some older Jupiter GPS Modules somewhere, is it worth testing one of those with your sketch?
your GPS module is different than GPS module used be me...
Deleteyou must identify the fields send by your module, see, for example, https://randomnerdtutorials.com/guide-to-neo-6m-gps-module-with-arduino/
Thanks once again, Nicu,
ReplyDeleteSo, if I utilise UBLOX U Centre application and configure GPS module to send GPVTG sentence, it should work?