Neo-6M Speedometer Issues

Hello friends and good evening :slight_smile: .

I am building a back to the future style speedometer using an Arduino Uno and a GPS module Neo-6m to drive, through a MAX7219, two common cathode seven-segment displays for speed reading. The code seems to work correctly as far as the display is concerned but unfortunately there is a huge delay in the speed data output which is sometimes not even received by moving the gps module, despite having raised the output rate of the Neo-6m At 10Hz and using the NeoGPS library.

Here is the code:

digita o i#include <LedControl.h>
#include <NMEAGPS.h>
#include<AltSoftSerial.h>
AltSoftSerial gps_port;

NMEAGPS gps;
gps_fix fix;
#define DIN   12
#define CLK   11
#define CS    10

LedControl lc = LedControl(DIN, CLK, CS, 1);

const unsigned char UBLOX_INIT[] PROGMEM = {
  0xB5, 0x62, 0x06, 0x08, 0x06, 0x00, 0x64, 0x00, 0x01, 0x00, 0x01, 0x00, 0x7A, 0x12, //(10Hz)
};
void setup()
{
  Serial.begin( 9600 );
  gps_port.begin( 9600 );
  lc.shutdown(0, false);
  lc.setIntensity(0, 15);
  lc.clearDisplay(0);
  for (unsigned int i = 0; i < sizeof(UBLOX_INIT); i++) {
    gps_port.write( pgm_read_byte(UBLOX_INIT + i) );
  }
}


void loop()
{
  if (gps.available( gps_port )) {
    fix = gps.read();
    displayspeed();
  }
}


void displayspeed()
{
  if (fix.valid.speed) {
    uint16_t knots = fix.spd.whole;

    static uint16_t averageKnots = 0;
    averageKnots = (averageKnots * 3) / 4  + knots;
    knots        = averageKnots / 4;

    // Convert to other units
    uint16_t mph = (knots * 1151L) / 1000L;
    Serial.println(knots);
    displaySpeed(mph); 

  }
}

void displaySpeed(float spd) {
  int ispd = int(spd);

  lc.clearDisplay(0);

  // Split the incoming speed into digits
  byte digit1 = byte((ispd / 10) % 10);
  byte digit0 = byte((ispd % 10));

  // Display the data and also implement Leading-Zero Blanking (LZB)
  lc.setDigit(0, 0, digit0, false);
  if (spd > 9.99)
  lc.setDigit(0, 1, digit1, false);
}

And this is the wiring schematic:

Maybe there's some interrupt going on but i have no idea of what could cause this issue. Any answer or ideas are highly appreciated.
Thanks in advance

try putting a serial.print after getting the fix, to ensure the speed is changing when you expect it to.

What do your NMEA sentences look like?

I I putted a Serial.print after the fix = gps.read () ;, and temporarily removed the void displayspeed () but the delay remains.
For NMEA sentences, do you mean the raw data collected with SoftwareSerial?

Yes, the raw data coming off the Neo's TX pin. There's much to learn from viewing the NMEA sentences.

If you send everything received by the software serial to the IDE monitor you will see them.

John.

Run this sketch to copy characters from the GPS to Serial Monitor. Turn on " Show timestamp" in Serial Monitor to get message timing. Then you can see if all the messages are arriving every tenth of a second.

#include <AltSoftSerial.h>
AltSoftSerial gps_port;

void setup()
{
  Serial.begin( 9600 );
  gps_port.begin( 9600 );
}

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

With your code I can clearly see the NMEA sentences, they are not transmitted at 10Hz but at 1Hz.
The delay in the speed value does not seem to be in the tx, that is, from when I move the gps to when the arduino receives the movement, seconds pass, but the transmission takes place correctly at 10Hz.

This are the Sentences:

You are getting samples once per second and averaging four of them. If the speed increases by 1 you will need 3 samples before the displayed average increases by 1.

What happens if you take out the averaging?

With no averaging i get a wandering speed, even when not moving sometimes it goes up to 4-5 and still when moving the module the update is not istantaneous.

Spurious speeds are an inherent characteristic of the GPS module as far as I can tell. It's in the nature of the entire system that the computed location will move around even if you are stationary. Nothing we can do about it. I don't know if averaging helps. If you take 4 readings and one is way out, then it shouldn't be included in the averaging.

I use a Neo-6M and it gives great performance at driving speeds but sometimes crazy speeds when stopped, say 126 kph. I ignore it. You could filter out spurious values in your code, say any that jump more than 10% from the previous. Or just don't worry about it.

Feed the NMEA sentences into the u-center software from u-blox. There's a great deal to be learned from using this software. You can see graphically how your position jumps around.

It s a pity that the forum does not have a section devoted to GPS. We keep rehashing the same topics.

Maybe set a treshold under low values can help that, the GPS is anyway not so precise especially on low speeds. I tried it 10 minutes ago in my car and works quite well and the response time is acceptable, maybe the problem was indeed the averaging code slowing down the output.
I wanted to use u-center but as far as i know i need a usb to serial converter, right?
i tried setting the arduino like that but u-center can't recognize anything...

Correct. If you already have an FTDI programming adapter, that IS a usb to serial converter.

Then why Arduino FTDI chip doesn't transmit the gps signals?

The FTDI adapter would transmit GPS coordinates, if it is fully functional and wired correctly. Connect FTDI RX to GPS TX, and GND to GND. Somehow you will have to power the GPS module.

You would need to run a terminal program or u-center on the computer to see them.

Be aware the GPS will only put out new information, i.e. the 'speed' @ 10Hz if it has time to do so.

With most all sentences enabled, there wont be time to send out all the sentences @10Hz if the baud rate is 9600.

Yes srnet i already thought of that and i wrote the specific codes for send only the NMEA sentence containing the speed value.
I leave the code below for anyone who want to replicate this project:

#include <LedControl.h>
#include <NMEAGPS.h>
#include<AltSoftSerial.h>
AltSoftSerial gps_port;

NMEAGPS gps;
gps_fix fix;
#define DIN   12
#define CLK   11
#define CS    10

LedControl lc = LedControl(DIN, CLK, CS, 1);

const unsigned char UBLOX_INIT[] PROGMEM = {
  // Rate (pick one)
  0xB5, 0x62, 0x06, 0x08, 0x06, 0x00, 0x64, 0x00, 0x01, 0x00, 0x01, 0x00, 0x7A, 0x12, //(10Hz)
  // 0xB5,0x62,0x06,0x08,0x06,0x00,0xC8,0x00,0x01,0x00,0x01,0x00,0xDE,0x6A, //(5Hz)
  // 0xB5,0x62,0x06,0x08,0x06,0x00,0xE8,0x03,0x01,0x00,0x01,0x00,0x01,0x39, //(1Hz)
  // Disable specific NMEA sentences
  0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x24, // GxGGA off
  0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x2B, // GxGLL off
  0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x32, // GxGSA off
  0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x39, // GxGSV off
  //0xB5,0x62,0x06,0x01,0x08,0x00,0xF0,0x04,0x00,0x00,0x00,0x00,0x00,0x01,0x04,0x40, // GxRMC off
  0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x05, 0x47 // GxVTG off
};
void setup()
{
  Serial.begin( 9600 );
  gps_port.begin( 9600 );
  lc.shutdown(0, false);
  lc.setIntensity(0, 15);
  lc.clearDisplay(0);
  for (unsigned int i = 0; i < sizeof(UBLOX_INIT); i++) {
    gps_port.write( pgm_read_byte(UBLOX_INIT + i) );
  }
}


void loop()
{
  if (gps.available( gps_port )) {
    fix = gps.read();
    Serial.println(fix.spd.whole);
    displayspeed();
  }
}

static const uint16_t MIN_KNOTS =   5;

void displayspeed()
{
  if (fix.valid.speed) {
    uint16_t knots = fix.spd.whole;
    if (knots < MIN_KNOTS)
      knots = 0;
    uint16_t mph = (knots * 1151L) / 1000L;
    displaySpeed(mph);

  }
}

void displaySpeed(float spd) {
  int ispd = int(spd);



  lc.clearDisplay(0);

  // Split the incoming speed into digits
  byte digit1 = byte((ispd / 10) % 10);
  byte digit0 = byte((ispd % 10));

  // Display the data and also implement Leading-Zero Blanking (LZB)
  lc.setDigit(0, 0, digit0, false);
  if (spd > 9.99)
    lc.setDigit(0, 1, digit1, false);
}

I am trying to do so, connecting arduino RESET to GND to use its FTDI chip and connecting GPS RX to arduino TX and GPS TX to Arduino RX but i don't see anything and u-center does not show position and other parameters...

That is a bad idea, because the FTDI RX and TX will be connected to other pins on the Arduino board. You might damage the board or the GPS module.

Just use the Arduino to echo the GPS output, as shown in reply #6, but dismiss the Arduino IDE and connect u-center to the serial port.

Many thanks, it works like a charm :smiley:
Now i can experiment with this fantastic software.

Well done.

Are you seeing the NMEA sentences in u-center?

Get your hands on a USB/TTL converter. They are cheap and so simple to use.

John.