Arduino GPS, trying to parse out SVN for visible satellites

Using a minimally modified code from tinyGPSPlus, I can draw my visible sats to tft. I want to label them as well w/SVN (ex: GPS18, GPS09, etc..) anyone know how to parse this out of the sat data?
Thx!

// XRAD'S SATELLITE TFT DISPLAY TRACKER
// Original code from Mikal Hart, found in GPS+ examples
// Modified by XRAD 4/30/22 because he wanted to see
// the overhead satellites.  Hardware: NEOM8N010 GPS,
// Adafruit 3.5 tft, Teensy 4.1. The azimuth and elevation
// are used to calculate x/y position and radius on the TFT, and
// SNR is used to calculate the radious of each visable satellite.
// Higher SNR means better signal, and those satellites nearer
// to 90 degree elevation are generally higher SNR, and display
// as larger radii on the TFT...cool!  Of course, you can
// do much more with the available satellite network strings.


#include <TinyGPSPlus.h>
#include <FastLED.h>//used for awesome built in timer!
#include <Adafruit_GFX.h>
#include "Adafruit_HX8357.h"//3.5" tft

//my tft control pins below. hardware MOSI,MISO,CLK as numSatrmal
#define TFT_CS 10
#define TFT_DC 9
#define TFT_RST -1 // RST can be set to -1 

#define TFT_LITE 23// for control tft led brightness/on/off

#define width 480
#define height 320

Adafruit_HX8357 tft = Adafruit_HX8357(TFT_CS, TFT_DC, TFT_RST);

static const int RXPin = 0, TXPin = 1; 

TinyGPSPlus gps;

static const int MAX_SATELLITES = 40;

TinyGPSCustom totalGPGSVMessages(gps, "GPGSV", 1); // $GPGSV sentence, first element
TinyGPSCustom messageNumber(gps, "GPGSV", 2);      // $GPGSV sentence, second element
TinyGPSCustom satsInView(gps, "GPGSV", 3);         // $GPGSV sentence, third element
TinyGPSCustom satNumber[4]; // to be initialized later
TinyGPSCustom elevation[4];
TinyGPSCustom azimuth[4];
TinyGPSCustom snr[4];

struct
{
  bool active;
  int elevation;
  int azimuth;
  int snr;
} sats[MAX_SATELLITES];

void clearSatMap() {
  tft.fillCircle(250, 140, 138, HX8357_BLACK);//just clear inside the GPS circle
  //draw the dotted cross
  for (int x = 55; x < 195; x++) {
    tft.drawPixel((2 * x), 140, HX8357_GREEN);
  }
  for (int y = 0; y < 140; y++) {
    tft.drawPixel(250, (2 * y), HX8357_GREEN);
  }
}


void drawSatMap() { //draw a map w/dotted cross. numSatTE: map is numSatt centered on tft!
  tft.drawRoundRect(110, 0, 280, 280, 10, HX8357_GREEN);
  
  for (int x =28; x < 98; x++) {
    tft.drawPixel((4 * x), 140, HX8357_GREEN);
  }
  for (int y = 0; y < 70; y++) {
    tft.drawPixel(250, (4 * y), HX8357_GREEN);
  }
  
  
  tft.drawCircle(250, 140, 140, HX8357_GREEN);
  tft.setCursor(245, 2);
  tft.fillRect(245, 2, 10, 14, HX8357_BLACK);
  tft.setTextColor(HX8357_GREEN);  tft.setTextSize(2);
  tft.println("N");
}

void setup() {
  Serial.begin(115200);
  Serial.flush();

  tft.begin();
  tft.setRotation(3);//horizontal

  pinMode(TFT_LITE, OUTPUT);
  digitalWrite(TFT_LITE, HIGH);//HIGH is ON, LOW is OFF

  tft.fillScreen(HX8357_BLACK);
  tft.setCursor(0, 80);
  tft.setTextSize(2);
  tft.setTextColor(HX8357_WHITE);
  tft.println("      XRAD'S SATELLITE TFT TRACKER");
  delay(2000);
  tft.fillScreen(HX8357_BLACK);
  drawSatMap();

  Serial1.begin(9600);//my GPS device uses 9600 baud, using teensy Serial1
  delay(100);

  Serial.print("XRAD'S SATELLITE TRACKER");
  Serial.println();

  // Initialize all the uninitialized TinyGPSCustom objects
  for (int i = 0; i < 4; ++i) {
    satNumber[i].begin(gps, "GPGSV", 4 + 4 * i); // offsets 4, 8, 12, 16
    elevation[i].begin(gps, "GPGSV", 5 + 4 * i); // offsets 5, 9, 13, 17
    azimuth[i].begin(  gps, "GPGSV", 6 + 4 * i); // offsets 6, 10, 14, 18
    snr[i].begin(      gps, "GPGSV", 7 + 4 * i); // offsets 7, 11, 15, 19
  }
}

void loop() {
  if (Serial1.available() > 0)// This is teensy hardware serial 1
  {
    gps.encode(Serial1.read());
    if (totalGPGSVMessages.isUpdated())//just GPS sats
    {
      for (int i = 0; i < 4; ++i)
      {
        int numSat = atoi(satNumber[i].value());
        if (numSat >= 1 && numSat <= MAX_SATELLITES)
        {
          sats[numSat - 1].elevation = atoi(elevation[i].value());
          sats[numSat - 1].azimuth = atoi(azimuth[i].value());
          sats[numSat - 1].snr = atoi(snr[i].value());
          sats[numSat - 1].active = true;
        }
      }

      int totalMessages = atoi(totalGPGSVMessages.value());
      int currentMessage = atoi(messageNumber.value());

      int A = 0;//angle 0-360
      int r = 0;//0 to 120

      if (totalMessages == currentMessage) {
        for (int i = 0; i < MAX_SATELLITES; ++i)
          if (sats[i].active) {

            //Serial.print(F(" Elevation="));
            //Serial.print(F(" "));
            //Serial.print(sats[i].elevation);
            r =  (sats[i].elevation); //convert to radius for satellite location
            //Serial.print(F(" "));
            int plotR = map(r, 0, 90, 130, 0);//map elevation to tft radius

            //Serial.print(F(" Azimuth="));
            //Serial.print(sats[i].azimuth);
            A = (sats[i].azimuth);//A is the angle which is converted to x,y
            A = A-90;//this is correction factor to rotate around plot axis to align w/numSatrth
            //Serial.print(F(" "));
            //Serial.print(F(" SNR="));
            //Serial.print(sats[i].snr);
            //Serial.print(F(" NEXT SATELLITE: "));
            int val = (sats[i].snr);
            int miniR = map(val, 0, 120, 1, 30);//map SNR to mini radius of each satellite

            if (r <= 130) {//don't draw outside the satellite map!
              //numSatw let's take the three elements from above and draw them on tft
              //with adafruit draw circle gfx routine!!
              tft.fillCircle( 250 + (plotR) * cos((A) * PI / 180 ), 140 + plotR * sin((A) * PI / 180 ), miniR, HX8357_WHITE);
            }
          }
        Serial.println();
        for (int i = 0; i < MAX_SATELLITES; ++i)
          sats[i].active = false;
      }
    }
  }
  EVERY_N_SECONDS(10) {//clear the old data off the tft every 'x' seconds
    //clearSatMap();
    drawSatMap();
  }
}


In the NMEA data provided by most GPS modules, satellite information is typically transmitted in the GSV (Satellites in View) sentence

make sure you receive this sentence from your unit (may be there is some configuration to do)

Thank you for reply! So i can get the data PRN, but i do not know how to parse out the satellite names....

$GNRMC,231430.00,V,,,,,,,070324,,,N*66

$GNVTG,,,,,,,,,N*2E

$GNGGA,231430.00,,,,,0,00,99.99,,,,,,*7F

$GNGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*2E 0 0 0 0 0 0 0 0 0 0 0 0

$GNGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*2E 0 0 0 0 0 0 0 0 0 0 0 0

$GPGSV,1,1,03,06,2

#include <TinyGPS++.h>
//#include <SoftwareSerial.h>
//static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 9600;

TinyGPSPlus gps;
//SoftwareSerial ss(RXPin, TXPin);

TinyGPSCustom gngsa[12] = {
  { gps, "GNGSA", 3 },
  { gps, "GNGSA", 4 },
  { gps, "GNGSA", 5 },
  { gps, "GNGSA", 6 },
  { gps, "GNGSA", 7 },
  { gps, "GNGSA", 8 },
  { gps, "GNGSA", 9 },
  { gps, "GNGSA", 10 },
  { gps, "GNGSA", 11 },
  { gps, "GNGSA", 12 },
  { gps, "GNGSA", 13 },
  { gps, "GNGSA", 14 }
};

static const int MAX_SATELLITES = 12;
int prns[MAX_SATELLITES];

void setup() {
  Serial.begin(115200);
  //ss.begin(GPSBaud);
  Serial1.begin(9600);
  Serial.println(F("ActiveSatellites.ino"));
  Serial.println();
}

void loop() {
  // Dispatch incoming characters
  if (Serial1.available() > 0) {
    char c = Serial1.read();
    Serial.write(c);  // Echo all GPS traffic
    if (gps.encode(c)) {
      // Something was encoded
      if (gngsa[0].isUpdated()) {
        // A $GNGSA message (ctive Satellites)

        // Gather the PRN numbers of the active satellites
        for (int i = 0; i < MAX_SATELLITES; ++i) {
          prns[i] = -1;
          if (gngsa[i].isValid()) {
            prns[i] = atoi(gngsa[i].value());
          }
        }

        // Display all the active PRN nunbers
        for (int i = 0; i < MAX_SATELLITES; ++i) {
          if (prns[i] != -1) {
            Serial.print(prns[i]);
            Serial.print(F(" "));
          }
        }
        Serial.println();
        delay(1000);
      }  // End of $GNGSA processing

    }  // End of gps.encode()
  }    // End of ss.available()
}

I should be more clear, I am looking for satellite ID tag, like G12..etc, not the number of visible/active satellites...

and how to separate out GLONASS and GPS from each other....
or GP,GA,GL,GB , etc...

the first question about this

is to make sure you do get the GSV sentence otherwise there will be nothing to work with.

if you take a small code (connecting the GPS Rx and Tx on a Serial port that is not used by the Serial monitor (depending on your arduino you'll have to use Software Serial) and just print out the information, that should et you know if you get that sentence or not. The example exists

THX JML,

Solution:


I was looking right at the answer the whole time...

 tft.setCursor(250 + (plotR)*cos((A)*PI / 180), 133 + plotR * sin((A)*PI / 180));
              tft.print(" ");
              if (sats[i].active) {
              tft.print(i);
              }
1 Like

Nice!

What the complete code that gives you that display on the TFT ?

srnet: read through post #1 it's mostly there. but you will have to substitute:

if (r <= 130) {//don't draw outside the satellite map!
              //now let's take the three elements from above and draw them on tft
              //with adafruit draw circle gfx routine!!
              tft.fillCircle( 250 + (plotR) * cos((A) * PI / 180 ), 140 + plotR * sin((A) * PI / 180 ), miniR, HX8357_WHITE);
            }

with:

if (plotR <= 130) {//don't draw outside the satellite map!

tft.fillCircle( 250 + (plotR) * cos((A) * PI / 180 ), 140 + plotR * sin((A) * PI / 180 ), miniR, HX8357_WHITE);
            
tft.setCursor(250 + (plotR)*cos((A)*PI / 180), 133 + plotR * sin((A)*PI / 180));
              tft.print(" ");
              tft.print(i);         
}

EDIT: shortened code a bit

and this is just for GPS sats. if you want to parse out GLONASS or others, you can. You just need the right code (tinyGPSplus) and receiver and antenna. I use ublox receivers series 8m and newer.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.