GY-GPS6MV2

I am pretty new to the Arduino/electronics world but like to learn through giving things a try.

The project I am working on is to measure the airflow, temperature and pressure of the air under a race car (the oil cooler that is mounted under the boot floor is not very effective so I want to see if the cooler fan is stalling, whether the air is too hot or if there just isn't enough air flowing). The airflow is being measured by mounting a PC cooler fan in a PVC pipe and using the third wire hall effect sensor to measure RPM and thus airflow. I have an MS5611 to take care of the pressure and temperature.

So far I have the airflow, temperature and pressure displaying on a 3.2" TFT (mounted to a Mega) but I am now trying to introduce a GPS module in order to display the car speed.

I have broken the GPS component out as a separate project for now and am using a UNO rather than the MEGA. I have a GY-GPS6MV2, which I believe is also referred to as a NEO-6 u-blox. I have tried several libraries but am currently trying TinyGPS.

The issue;

Inside the house the green LED on the GPS module does not blink so I realise that I am not connecting with any satellites and getting a signal. I am connected to a PC so cannot use the serial monitor as the code requires when outside. This code is borrowed from

although I have removed the references to the LCD screen.

In order to be able to connect to a wall charger and move outside I have further modified the code to illuminate an LED once the gpsSerial.available() is true i.e. it starts receiving a signal. This is a quick and dirty to just make sure a signal is received.

My code:

#include <SoftwareSerial.h> 
#include <TinyGPS.h> 
float lat = 28.5458,lon = 77.1703; // create variable for latitude and longitude object  
SoftwareSerial gpsSerial(3,4);//rx,tx 

TinyGPS gps; // create gps object 
void setup(){ 
Serial.begin(9600); // connect serial 
//Serial.println("The GPS Received Signal:"); 
gpsSerial.begin(9600); // connect gps sensor 

//myadded bit
pinMode(12, OUTPUT);
pinMode(13, OUTPUT);

digitalWrite(13,LOW);
digitalWrite(12,LOW);
} 
void loop(){ 
  while(gpsSerial.available()){ // check for gps data 
  if(gps.encode(gpsSerial.read()))// encode gps data 
  {  
  gps.f_get_position(&lat,&lon); // get latitude and longitude 
  // display position 
  
  Serial.print("Position: "); 
  Serial.print("Latitude:"); 
  Serial.print(lat,6); 
  Serial.print(";"); 
  Serial.print("Longitude:"); 
  Serial.println(lon,6);  
 
  //Serial.print(lat); 
  //Serial.print(" ");  

  //myadded bit
  digitalWrite(13,HIGH);
  digitalWrite(12,LOW);
 } 
} 
String latitude = String(lat,6); 
  String longitude = String(lon,6); 
Serial.println(latitude+";"+longitude); 
delay(1000); 
}

Picture of my wiring attached.

When I am inside the serial monitor only ever shows 28.5458;77.1703 i.e. the variable values of latitude and longitude as defined at the beginning of the code. I presume it is not getting a signal so the "while(gpsSerial.available())" is failing.

Outside the LED does NOT light also meaning no signal yet the green LED on the GPS unit is flashing.

I am at a loss. As far as I can see I have everything correct. I am inexperienced at this so I could easily have overlooked something!!!!

While I have you helping, ultimately I want to grab the GPS speed (not interested in lat and long) so is there a simple function (gps.speed()???) to grab that without additional maths?

It is difficult to tell from your 'photo, but are you sure that you have got the Tx and Rx connections to the GPS the right way round ?

One thing that is definitely wrong is that you have no limiting resistors on the LEDs

You claim that you are lighting the LED when there is data from the GPS, but that is not true. You light the LEDs only when there is VALID data from the GPS. That can take as much as 20 minutes to happen. The first time, not subsequent times.

If you can Serial.print() the valid data, you can Serial.print() the actual data from the GPS, WITHOUT attempting to parse it.

Perhaps a clue by four will present itself. Duck!

One thing that is definitely wrong is that you have no limiting resistors on the LEDs

That's OK. They never get turned on.

UKHeliBob -GPS Tx is going to pin4 and GPS Rx to pin3. I believe that is correct. I know I should have resistors with the LEDs but I didn't have any so I am living on the edge!

PaulS - you lost me at hello......

PaulS:
You claim that you are lighting the LED when there is data from the GPS, but that is not true. You light the LEDs only when there is VALID data from the GPS. That can take as much as 20 minutes to happen. The first time, not subsequent times.

Are you saying that "gps.Serial.available()" is not seeing if just any old data is available from the GPS unit? Not sure what you mean by VALID data (I told you I am inexperienced - be gentle with me!!).

So if my idea with the LEDs is flawed, how can I establish why I am not getting data into the serial monitor i.e. why is it skipping past the "while" statement section?????

GPS Tx is going to pin4 and GPS Rx to pin3.

SoftwareSerial gpsSerial(3, 4); //rx,tx

So you have GPS Tx going to gpsSerial Tx and GPS Rx going to gpsSerial Rx

Think carefully about that.
When the GPS transmits shouldn't there be something to receive it ?

Are you saying that "gps.Serial.available()" is not seeing if just any old data is available from the GPS unit? Not sure what you mean by VALID data (I told you I am inexperienced - be gentle with me!!).

gpsSerial.available() tells you how much data is available in the buffer that the Arduino put the data that the GPS sent into. It tells you nothing about whether that data was a valid NMEA sentence or a poem in ancient Sanskrit. YOU need to decide that before trying to parse the poem.

Your loop() function should have, for now, just:

void loop()
{
   if(gpsSerial.available() > 0)
   {
      char gpsCrap = gpsSerial.read();
      Serial.print(gpsCrap);
   }
}

If you see data in the serial monitor that looks like valid NMEA data, then you can do one thing. If you see data that looks like a poem in ancient Sanskrit, translated to Chinese, then you need to do something different. If you see nothing, then the helicopter guy's advice heeds warranting.

Paul, Heli,

Changing the wires now sees data flowing into the serial monitor albeit missing alot of the info due to no connection to the satellites.

I will either have to grab a laptop to take the board and serial monitor outside or maybe use a TFT in some way.

I think I have enough to get on with so cheers!

I have attached the data that was outputted using Paul's simplified test code. It looks like GPS data to my untrained eye (no poems or sanskrit) so the gpsSerial.read() seems to be working fine.

Previously I thought the While statement was false but it is actually the if(gps.encode(gpsSerial.read())) that I presume is returning a false. I do not understand why as I don't understand what the gpd.encode function is doing (I tried looking in the .cpp file).

Baud set to 9600 as per what the GPS packaging states.

I have drawn another blank......

I do not understand why as I don't understand what the gpd.encode function is doing

gps.encode() returns false when the supplied character is not the end of a sentence character. It returns true when it is, and the checksum for the sentence matches the checksum IN the sentence.

The checksum is always two characters, so after two characters are received after the * arrives, the checksum is calculated and compared to that of the last two characters.

cheers

I am sorry but I have spent ALL day playing with this and cannot move forwards. I am really trying not to outstay my welcome with you all!

I have now proved that the GPS unit is connecting to satellites by using Paul's basic gps.read code. The Data2.jpg file attached shows what I am getting. The only possible issue might be that the $GPRMC sentence does not have a 'Track Angle' although it does have the , either side of its position in the sentence so doubt if it is a concern. 5 satellites tracked - tick.

I have ploughed through the TinyGPS.CPP file to try to understand why the If(gps.encode(gpsSerial.read())) statement is returning a False but I have too many holes in my programming knowledge to work much out. I have not modified the TinyGPS library in any way from what I downloaded off GitHub.

This is the code as it stands (close to how it was in the original post);

#include <LiquidCrystal.h>
#include <SoftwareSerial.h> 
#include <TinyGPS.h> 

float lat = 11.1111,lon = 22.2222; // create variable for latitude and longitude object  

SoftwareSerial gpsSerial(3,4);//rx,tx 
LiquidCrystal lcd(A0,A1,A2,A3,A4,A5); 
TinyGPS gps; // create gps object 

void setup()
  { 
  Serial.begin(9600); // connect serial  
  gpsSerial.begin(9600); // connect gps sensor 
  
  lcd.begin(16,2);
  lcd.setCursor(1,0); 
  lcd.print("GPS Setup..."); 
  delay(5000);
  gpsSerial.read();
  } 

void loop(){ 
 
  while(gpsSerial.available()){ // check for gps data 
    // this has been added so that I know that the WHILE stmt returned TRUE
    lcd.clear(); 
    delay(2000);    
    lcd.setCursor(1,0); 
    lcd.print("Something Avail");
    delay(2000);

    
    if(gps.encode(gpsSerial.read()))// encode gps data 
      {     
      gps.f_get_position(&lat,&lon); // get latitude and longitude 
      
      // display position LCD
      lcd.clear(); 
      lcd.setCursor(1,0); 
      lcd.print("LAT:"); 
      lcd.setCursor(5,0); 
      lcd.print(lat);  
      lcd.setCursor(0,1); 
      lcd.print(",LON:"); 
      lcd.setCursor(5,1); 
      lcd.print(lon); 

      // display position monitor
      Serial.print("Position: "); 
      Serial.print("Latitude:"); 
      Serial.print(lat,6); 
      Serial.print(";"); 
      Serial.print("Longitude:"); 
      Serial.println(lon,6); 
      } 
 
    delay(2000);
  } 
  
String latitude = String(lat,6); 
String longitude = String(lon,6); 
Serial.println(latitude+";"+longitude); 

// added so that I know if the code has fallen out of the WHILE stmt
lcd.clear();
lcd.setCursor(1,0);  
lcd.print("OUTSIDE WHILE");
delay(2000); 

/*
// PaulS code to check sentences * 
if(gpsSerial.available() > 0)
   {
      char gpsCrap = gpsSerial.read();
      Serial.print(gpsCrap);
   }
*/
}

I put a couple of lcd.print commands in the code so that I would have a visual prompt as to where in the code it was running at (yes yes this is probably a very noob thing to do but it helped me :confused: ).

The code is definitely not falling out of the While loop but is not entering the if(gps.encode(gpsSerial.read())) as said before.

I have tried my best but I am on my knees and need somebody in the know to help work out why the code is failing. As PaulS said before it seems probable that the checksum is failing but IDK. The only other query I have is that there is a part in the TinyGPS.h header file that is commented out that might look suspicious to my untrained eye???;

#define _GPS_VERSION 13 // software version of this library
#define _GPS_MPH_PER_KNOT 1.15077945
#define _GPS_MPS_PER_KNOT 0.51444444
#define _GPS_KMPH_PER_KNOT 1.852
#define _GPS_MILES_PER_METER 0.00062137112
#define _GPS_KM_PER_METER 0.001
// #define _GPS_NO_STATS

It's getting late and my head hurts!

The only possible issue might be that the $GPRMC sentence does not have a 'Track Angle' although it does have the , either side of its position in the sentence

Is the GPS unit stationary or moving ?

To get a track angle it needs to be moving otherwise there is no track to have an angle

  lcd.print("GPS Setup...");
  delay(5000);
  gpsSerial.read();
  }

What is that call to read() doing there?

yes yes this is probably a very noob thing to do

You misspelled good.

The code is definitely not falling out of the While loop

That's because the GPS is sending several hundred characters per second, and you are delay()ing WAY too much, and loosing data. Get rid of the delay()s in the while loop. You MUST read data as fast as possible.

Do not write to the LCD in the while loop, either. That is a very slow device.

You can do Serial.print(), but not at stone age speeds. Get the speed up to 115200.

In the TinyGPS.cpp file (you really should be using TinyGPS++, instead), you can add Serial.print() statements in the encode() method, to see what it gets, and what it does when the character is a *.

The GPS was not moving so now I understand why no Track Angle.

That gpsSerial.read() is a hang over from my testing that I forgot to remove. I had a thought that the while statement was always finding something not because new data was available but because the old data had not been read and deleted. Just playing in hope. I will remove it.

All the delays were to help me watch the LCD and see the updates easier. Missing gps data I presume is an issue once this whole thing is working and is not part of my current issue?

When you say to add Serial.print() statements in the encode() method do I do that in the .CPP file? I guess I can output the various variables to assist with working out what is wrong?

I will look at a move to TinyGPS++.

you really should be using TinyGPS++, instead

Or something even smaller, faster, more reliable and more accurate, like NeoGPS?

Like PaulS has said, using delay is the major problem. The TinyGPS examples make you think it's ok to use delay in your sketch. It's not. While the Arduino twiddles its thumbs doing a delay, the GPS device continues to send characters. After 64ms, the gpsSerial input buffer is full, the Arduino starts losing characters. This prevents any new GPS fields from being parsed correctly (more info here.)

Another problem with other libraries' examples is that they try to print too much data. While the Arduino waits for the print characters to be sent to the PC, the GPS device continues to send characters. Eventually...

You get the picture? You must continually read the GPS characters, or the Arduino will start losing them.

Here is a NeoGPS version of your sketch:

#include <LiquidCrystal.h>
#include <NeoSWSerial.h>
#include <NMEAGPS.h>

NMEAGPS gps; // parser
gps_fix fix; // create variable for latitude, longitude, speed, altitude, etc.

NeoSWSerial gpsSerial(3,4);//rx,tx
LiquidCrystal lcd(A0,A1,A2,A3,A4,A5);

void setup()
{
  Serial.begin(9600); // connect serial
  gpsSerial.begin(9600); // connect gps sensor

  lcd.begin(16,2);
  lcd.setCursor(1,0);
  lcd.print("GPS Setup...");
}

void loop()
{

  while(gps.available( gpsSerial )) { // check for gps data

    lcd.setCursor(1,0);
    lcd.print("Something Avail");

    fix = gps.read(); // get a complete fix "structure", once per second
      // This structure contains all the pieces that were parsed
      // from the NMEA sentences sent by the GPS device.

    // display position LCD
    lcd.clear();
    lcd.setCursor(1,0);
    lcd.print("LAT:");
    if (fix.valid.location) {
      // Only print a value if the GPS knows the location
      lcd.setCursor(5,0);
      lcd.print( fix.latitude() );  // <-- get the latitude from the fix structure
    }
    lcd.setCursor(0,1);
    lcd.print(",LON:");
    if (fix.valid.location) {
      lcd.setCursor(5,1);
      lcd.print( fix.longitude() );
    }

    // display position monitor
    Serial.print("Position: ");
    Serial.print("Latitude:");
    if (fix.valid.location)
      Serial.print( fix.latitude(), 6 );
    Serial.print(";");
    Serial.print("Longitude:");
    if (fix.valid.location)
      Serial.print( fix.longitude(), 6 );
    Serial.println();
  }
}

Notice that it never uses delay.

Also notice that it does not print invalid locations. Your GPS device may not know the location yet, usually because it is not receiving good signals from the satellites. Other libraries' examples blindly print GPS fields, even if the GPS did not send them! NeoGPS provides validity flags that you can test, before using an "empty" value.

It's not obvious from the sketch, but NeoGPS also guarantees that your LCD will update only once per second. Other libraries can cause the LCD to flicker, because they update between 2 and 5 times per second. NeoGPS gathers up all the fields that the GPS device is sending, and provides 1 update with all the pieces. They are all inside the fix structure (see the docs for all the pieces).

I should also mention that there are much better alternatives to SoftwareSerial. It is very inefficient, because it disables interrupts for long periods of time. This will interfere with other parts of your sketch, or with other libraries. Other choices described here.

The above sketch uses NeoSWSerial on pins 3 & 4. That's so you can try it without rewiring. But, if you read the above link on choosing a serial port, you might want to switch to pins 8 & 9 so you can use AltSoftSerial. It is the best software serial library. Even if you don't try NeoGPS, I would suggest switching to those pins.

If you want to try it, NeoSWSerial and NeoGPS are available from the IDE Library Manager, under the menu Sketch -> Include Library -> Manage Libraries.

BTW, the NeoGPS examples expect your GPS to be on the AltSoftSerial pins. If you want to try one of the examples, and continue to use pins 3 & 4, you must edit the default Arduino/Libraries/NeoGPS/src/GPSport.h. Delete everything in that file and replace it with this:

#ifndef GPSport_h
#define GPSport_h

#include <NeoSWSerial.h>
NeoSWSerial gpsPort(3,4);//rx (to GPS tx), tx (to GPS rx)
#define GPS_PORT_NAME "NeoSWSerial( 3, 4 )"
#define DEBUG_PORT Serial

#endif

For the best results, I would also suggest changing this line in Arduino/Libraries/NeoGPS/src/NMEAGPS_cfg.h:

#define LAST_SENTENCE_IN_INTERVAL NMEAGPS::NMEA_GLL

The default is RMC, but the NEO-6M module you have sends the GLL sentence.

-dev, I did originally load up the NeoGPS and NeoSWSerial libraries but cannot remember why I didn't use them. Ultimately after all this experimentation all I want to get from the GPS is the speed. Can I assume that in the code you provided above that it will be as simple as changing fix.latitude to something like fix.speed?

Mk1_Oz:
all I want to get from the GPS is the speed... as simple as changing fix.latitude() to something like fix.speed()?

Yes:

    lcd.print("SPEED:");
    if (fix.valid.speed) {
      lcd.setCursor(5,1);
      lcd.print( fix.speed() );
    }

Here's a post with links to several speedometer projects.

Awesome help...ty

I forgot to mention that you can request the speed in several different units. From the NeoGPS Data Model page:

...this fix variable (or any other variable of type gps_fix) contains the following members:
** .**
** .**
** .**
● a speed, accessed with
fix.speed_kph(), in floating-point kilometers per hour
fix.speed_mph(), in floating-point miles per hour
fix.speed(), in floating-point knots (nautical miles per hour)
fix.speed_mkn(), in integer knots, scaled by 1000
fix.spd.whole, in integer knots
fix.spd.frac, in integer thousandths of a knot, to be added to the whole part

My last reply showed how to get the speed in nautucal miles per hour.